xref: /xv6-public/fs.c (revision 1dca3afb)
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 
27f5527388Srsc // Allocate a disk block.
2824111398Skaashoek static uint
2924111398Skaashoek balloc(uint dev)
3024111398Skaashoek {
3124111398Skaashoek   int b;
3224111398Skaashoek   struct buf *bp;
3324111398Skaashoek   struct superblock *sb;
3428d9ef04Skaashoek   int bi = 0;
3524111398Skaashoek   int size;
3624111398Skaashoek   int ninodes;
3724111398Skaashoek   uchar m;
3824111398Skaashoek 
3924111398Skaashoek   bp = bread(dev, 1);
4024111398Skaashoek   sb = (struct superblock*) bp->data;
4124111398Skaashoek   size = sb->size;
4224111398Skaashoek   ninodes = sb->ninodes;
4324111398Skaashoek 
4424111398Skaashoek   for(b = 0; b < size; b++) {
4524111398Skaashoek     if(b % BPB == 0) {
4624111398Skaashoek       brelse(bp);
4724111398Skaashoek       bp = bread(dev, BBLOCK(b, ninodes));
4824111398Skaashoek     }
4924111398Skaashoek     bi = b % BPB;
5024111398Skaashoek     m = 0x1 << (bi % 8);
5124111398Skaashoek     if((bp->data[bi/8] & m) == 0) {  // is block free?
5224111398Skaashoek       break;
5324111398Skaashoek     }
5424111398Skaashoek   }
5524111398Skaashoek   if(b >= size)
562aa4c3bcSrtm     panic("balloc: out of blocks");
5724111398Skaashoek 
5824111398Skaashoek   bp->data[bi/8] |= 0x1 << (bi % 8);
5905e97551Srtm   bwrite(bp, BBLOCK(b, ninodes));  // mark it allocated on disk
6028d9ef04Skaashoek   brelse(bp);
6124111398Skaashoek   return b;
6224111398Skaashoek }
6324111398Skaashoek 
6428d9ef04Skaashoek static void
6528d9ef04Skaashoek bfree(int dev, uint b)
6628d9ef04Skaashoek {
6728d9ef04Skaashoek   struct buf *bp;
6828d9ef04Skaashoek   struct superblock *sb;
6928d9ef04Skaashoek   int bi;
7028d9ef04Skaashoek   int ninodes;
7128d9ef04Skaashoek   uchar m;
7228d9ef04Skaashoek 
7328d9ef04Skaashoek   bp = bread(dev, 1);
7428d9ef04Skaashoek   sb = (struct superblock*) bp->data;
7528d9ef04Skaashoek   ninodes = sb->ninodes;
7628d9ef04Skaashoek   brelse(bp);
7728d9ef04Skaashoek 
78c372e8dcSkaashoek   bp = bread(dev, b);
79c372e8dcSkaashoek   memset(bp->data, 0, BSIZE);
80c372e8dcSkaashoek   bwrite(bp, b);
81c372e8dcSkaashoek   brelse(bp);
82c372e8dcSkaashoek 
8328d9ef04Skaashoek   bp = bread(dev, BBLOCK(b, ninodes));
8428d9ef04Skaashoek   bi = b % BPB;
8528d9ef04Skaashoek   m = ~(0x1 << (bi %8));
8628d9ef04Skaashoek   bp->data[bi/8] &= m;
8705e97551Srtm   bwrite(bp, BBLOCK(b, ninodes));  // mark it free on disk
8828d9ef04Skaashoek   brelse(bp);
8928d9ef04Skaashoek }
9024111398Skaashoek 
91f5527388Srsc // Find the inode with number inum on device dev
92f5527388Srsc // and return an in-memory copy.  Loads the inode
93f5527388Srsc // from disk into the in-core table if necessary.
94f5527388Srsc // The returned inode has busy set and has its ref count incremented.
95f5527388Srsc // Caller must iput the return value when done with it.
9611a9947fSrtm struct inode*
9711a9947fSrtm iget(uint dev, uint inum)
9811a9947fSrtm {
9917e3cf15Srtm   struct inode *ip, *nip;
10011a9947fSrtm   struct dinode *dip;
10111a9947fSrtm   struct buf *bp;
10211a9947fSrtm 
10311a9947fSrtm   acquire(&inode_table_lock);
10411a9947fSrtm 
10511a9947fSrtm  loop:
10617e3cf15Srtm   nip = 0;
10711a9947fSrtm   for(ip = &inode[0]; ip < &inode[NINODE]; ip++){
10811a9947fSrtm     if(ip->count > 0 && ip->dev == dev && ip->inum == inum){
10911a9947fSrtm       if(ip->busy){
11011a9947fSrtm         sleep(ip, &inode_table_lock);
11111a9947fSrtm         goto loop;
11211a9947fSrtm       }
11311a9947fSrtm       ip->count++;
11417a85657Srtm       ip->busy = 1;
11511a9947fSrtm       release(&inode_table_lock);
11611a9947fSrtm       return ip;
11711a9947fSrtm     }
11811a9947fSrtm     if(nip == 0 && ip->count == 0)
11911a9947fSrtm       nip = ip;
12011a9947fSrtm   }
12111a9947fSrtm 
12211a9947fSrtm   if(nip == 0)
12311a9947fSrtm     panic("out of inodes");
12411a9947fSrtm 
12511a9947fSrtm   nip->dev = dev;
12611a9947fSrtm   nip->inum = inum;
12711a9947fSrtm   nip->count = 1;
12811a9947fSrtm   nip->busy = 1;
12911a9947fSrtm 
13011a9947fSrtm   release(&inode_table_lock);
13111a9947fSrtm 
13224111398Skaashoek   bp = bread(dev, IBLOCK(inum));
13311a9947fSrtm   dip = &((struct dinode*)(bp->data))[inum % IPB];
13411a9947fSrtm   nip->type = dip->type;
135e8d11c2eSkaashoek   nip->major = dip->major;
136e8d11c2eSkaashoek   nip->minor = dip->minor;
13711a9947fSrtm   nip->nlink = dip->nlink;
13811a9947fSrtm   nip->size = dip->size;
13911a9947fSrtm   memmove(nip->addrs, dip->addrs, sizeof(nip->addrs));
14011a9947fSrtm   brelse(bp);
14111a9947fSrtm 
14211a9947fSrtm   return nip;
14311a9947fSrtm }
14411a9947fSrtm 
14528d9ef04Skaashoek void
14628d9ef04Skaashoek iupdate(struct inode *ip)
14728d9ef04Skaashoek {
14828d9ef04Skaashoek   struct buf *bp;
14928d9ef04Skaashoek   struct dinode *dip;
15028d9ef04Skaashoek 
15128d9ef04Skaashoek   bp = bread(ip->dev, IBLOCK(ip->inum));
15228d9ef04Skaashoek   dip = &((struct dinode*)(bp->data))[ip->inum % IPB];
15328d9ef04Skaashoek   dip->type = ip->type;
15428d9ef04Skaashoek   dip->major = ip->major;
15528d9ef04Skaashoek   dip->minor = ip->minor;
15628d9ef04Skaashoek   dip->nlink = ip->nlink;
15728d9ef04Skaashoek   dip->size = ip->size;
15828d9ef04Skaashoek   memmove(dip->addrs, ip->addrs, sizeof(ip->addrs));
15905e97551Srtm   bwrite(bp, IBLOCK(ip->inum));   // mark it allocated on the disk
16028d9ef04Skaashoek   brelse(bp);
16128d9ef04Skaashoek }
16228d9ef04Skaashoek 
163e8d11c2eSkaashoek struct inode*
164e8d11c2eSkaashoek ialloc(uint dev, short type)
165e8d11c2eSkaashoek {
166e8d11c2eSkaashoek   struct inode *ip;
167e8d11c2eSkaashoek   struct dinode *dip = 0;
168e8d11c2eSkaashoek   struct superblock *sb;
169e8d11c2eSkaashoek   int ninodes;
170e8d11c2eSkaashoek   int inum;
171e8d11c2eSkaashoek   struct buf *bp;
172e8d11c2eSkaashoek 
173e8d11c2eSkaashoek   bp = bread(dev, 1);
17424111398Skaashoek   sb = (struct superblock*) bp->data;
175e8d11c2eSkaashoek   ninodes = sb->ninodes;
176e8d11c2eSkaashoek   brelse(bp);
177e8d11c2eSkaashoek 
178e8d11c2eSkaashoek   for(inum = 1; inum < ninodes; inum++) {  // loop over inode blocks
17924111398Skaashoek     bp = bread(dev, IBLOCK(inum));
180e8d11c2eSkaashoek     dip = &((struct dinode*)(bp->data))[inum % IPB];
181e8d11c2eSkaashoek     if(dip->type == 0) {  // a free inode
182e8d11c2eSkaashoek       break;
183e8d11c2eSkaashoek     }
184e8d11c2eSkaashoek     brelse(bp);
185e8d11c2eSkaashoek   }
186e8d11c2eSkaashoek 
18717e3cf15Srtm   if(inum >= ninodes)
1882aa4c3bcSrtm     panic("ialloc: no inodes left");
189e8d11c2eSkaashoek 
1902aa4c3bcSrtm   memset(dip, 0, sizeof(*dip));
191e8d11c2eSkaashoek   dip->type = type;
19205e97551Srtm   bwrite(bp, IBLOCK(inum));   // mark it allocated on the disk
193e8d11c2eSkaashoek   brelse(bp);
194e8d11c2eSkaashoek   ip = iget(dev, inum);
195e8d11c2eSkaashoek   return ip;
196e8d11c2eSkaashoek }
197e8d11c2eSkaashoek 
19828d9ef04Skaashoek static void
19924437cd5Skaashoek ifree(struct inode *ip)
200e8d11c2eSkaashoek {
20128d9ef04Skaashoek   ip->type = 0;
20228d9ef04Skaashoek   iupdate(ip);
203e8d11c2eSkaashoek }
204e8d11c2eSkaashoek 
20511a9947fSrtm void
2069d3fb671Srtm ilock(struct inode *ip)
2079d3fb671Srtm {
2089d3fb671Srtm   if(ip->count < 1)
2099d3fb671Srtm     panic("ilock");
2109d3fb671Srtm 
2119d3fb671Srtm   acquire(&inode_table_lock);
2129d3fb671Srtm 
2139d3fb671Srtm   while(ip->busy)
2149d3fb671Srtm     sleep(ip, &inode_table_lock);
2159d3fb671Srtm   ip->busy = 1;
2169d3fb671Srtm 
2179d3fb671Srtm   release(&inode_table_lock);
2189d3fb671Srtm }
2199d3fb671Srtm 
2209d3fb671Srtm // caller is holding onto a reference to this inode, but no
2219d3fb671Srtm // longer needs to examine or change it, so clear ip->busy.
2229d3fb671Srtm void
2239d3fb671Srtm iunlock(struct inode *ip)
2249d3fb671Srtm {
22517e3cf15Srtm   if(ip->busy != 1 || ip->count < 1)
2269d3fb671Srtm     panic("iunlock");
2279d3fb671Srtm 
2289d3fb671Srtm   acquire(&inode_table_lock);
2299d3fb671Srtm 
2309d3fb671Srtm   ip->busy = 0;
2319d3fb671Srtm   wakeup(ip);
2329d3fb671Srtm 
2339d3fb671Srtm   release(&inode_table_lock);
2349d3fb671Srtm }
2359d3fb671Srtm 
23622bac2cbSkaashoek uint
23722bac2cbSkaashoek bmap(struct inode *ip, uint bn)
23822bac2cbSkaashoek {
23922bac2cbSkaashoek   unsigned x;
240ea2909b6Skaashoek   uint *a;
241ea2909b6Skaashoek   struct buf *inbp;
24222bac2cbSkaashoek 
243ea2909b6Skaashoek   if(bn >= MAXFILE)
24422bac2cbSkaashoek     panic("bmap 1");
245ea2909b6Skaashoek   if(bn < NDIRECT) {
24622bac2cbSkaashoek     x = ip->addrs[bn];
24722bac2cbSkaashoek     if(x == 0)
24822bac2cbSkaashoek       panic("bmap 2");
249ea2909b6Skaashoek   } else {
2505051da6dSrtm     if(ip->addrs[INDIRECT] == 0)
2515051da6dSrtm       panic("bmap 3");
2521be76685Skaashoek     inbp = bread(ip->dev, ip->addrs[INDIRECT]);
253ea2909b6Skaashoek     a = (uint*) inbp->data;
254ea2909b6Skaashoek     x = a[bn - NDIRECT];
255ea2909b6Skaashoek     brelse(inbp);
256ea2909b6Skaashoek     if(x == 0)
2575051da6dSrtm       panic("bmap 4");
258ea2909b6Skaashoek   }
25922bac2cbSkaashoek   return x;
26022bac2cbSkaashoek }
26122bac2cbSkaashoek 
26222bac2cbSkaashoek void
2632aa4c3bcSrtm itrunc(struct inode *ip)
26422bac2cbSkaashoek {
265ea2909b6Skaashoek   int i, j;
2661be76685Skaashoek   struct buf *inbp;
26722bac2cbSkaashoek 
268ea2909b6Skaashoek   for(i = 0; i < NADDRS; i++) {
26922bac2cbSkaashoek     if(ip->addrs[i] != 0) {
270ea2909b6Skaashoek       if(i == INDIRECT) {
2711be76685Skaashoek         inbp = bread(ip->dev, ip->addrs[INDIRECT]);
2721be76685Skaashoek         uint *a = (uint*) inbp->data;
273bcfb84b6Srtm         for(j = 0; j < NINDIRECT; j++) {
274ea2909b6Skaashoek           if(a[j] != 0) {
275ea2909b6Skaashoek             bfree(ip->dev, a[j]);
276ea2909b6Skaashoek             a[j] = 0;
277ea2909b6Skaashoek           }
278ea2909b6Skaashoek         }
2791be76685Skaashoek         brelse(inbp);
280ea2909b6Skaashoek       }
28122bac2cbSkaashoek       bfree(ip->dev, ip->addrs[i]);
28222bac2cbSkaashoek       ip->addrs[i] = 0;
28322bac2cbSkaashoek     }
28422bac2cbSkaashoek   }
28522bac2cbSkaashoek   ip->size = 0;
28622bac2cbSkaashoek   iupdate(ip);
28722bac2cbSkaashoek }
28822bac2cbSkaashoek 
2899d3fb671Srtm // caller is releasing a reference to this inode.
2909d3fb671Srtm // you must have the inode lock.
2919d3fb671Srtm void
29211a9947fSrtm iput(struct inode *ip)
29311a9947fSrtm {
2949d3fb671Srtm   if(ip->count < 1 || ip->busy != 1)
2959d3fb671Srtm     panic("iput");
2969d3fb671Srtm 
2972aa4c3bcSrtm   if((ip->count == 1) && (ip->nlink == 0)) {
2982aa4c3bcSrtm     itrunc(ip);
2992aa4c3bcSrtm     ifree(ip);
3002aa4c3bcSrtm   }
30122bac2cbSkaashoek 
30211a9947fSrtm   acquire(&inode_table_lock);
30311a9947fSrtm 
30411a9947fSrtm   ip->count -= 1;
30511a9947fSrtm   ip->busy = 0;
30611a9947fSrtm   wakeup(ip);
30711a9947fSrtm 
30811a9947fSrtm   release(&inode_table_lock);
30911a9947fSrtm }
3109d3fb671Srtm 
3119d3fb671Srtm void
31232630628Srtm idecref(struct inode *ip)
3139d3fb671Srtm {
314211ff0c6Srtm   ilock(ip);
315211ff0c6Srtm   iput(ip);
3169d3fb671Srtm }
3179d3fb671Srtm 
3181f544842Skaashoek void
319e958c538Skaashoek iincref(struct inode *ip)
320e958c538Skaashoek {
321e958c538Skaashoek   ilock(ip);
322e958c538Skaashoek   ip->count++;
323e958c538Skaashoek   iunlock(ip);
324e958c538Skaashoek }
325e958c538Skaashoek 
326e958c538Skaashoek void
3271f544842Skaashoek stati(struct inode *ip, struct stat *st)
3281f544842Skaashoek {
329*1dca3afbSrsc   st->dev = ip->dev;
330*1dca3afbSrsc   st->ino = ip->inum;
331*1dca3afbSrsc   st->type = ip->type;
332*1dca3afbSrsc   st->nlink = ip->nlink;
333*1dca3afbSrsc   st->size = ip->size;
3341f544842Skaashoek }
3351f544842Skaashoek 
33622bac2cbSkaashoek #define min(a, b) ((a) < (b) ? (a) : (b))
33722bac2cbSkaashoek 
338c59361f1Srtm int
33917a85657Srtm readi(struct inode *ip, char *dst, uint off, uint n)
340c59361f1Srtm {
341c59361f1Srtm   uint target = n, n1;
342c59361f1Srtm   struct buf *bp;
343c59361f1Srtm 
344939f9edeSkaashoek   if(ip->type == T_DEV) {
345*1dca3afbSrsc     if(ip->major < 0 || ip->major >= NDEV || !devsw[ip->major].read)
346939f9edeSkaashoek       return -1;
347*1dca3afbSrsc     return devsw[ip->major].read(ip->minor, dst, n);
348939f9edeSkaashoek   }
349939f9edeSkaashoek 
350c59361f1Srtm   while(n > 0 && off < ip->size){
35124111398Skaashoek     bp = bread(ip->dev, bmap(ip, off / BSIZE));
352c59361f1Srtm     n1 = min(n, ip->size - off);
35324111398Skaashoek     n1 = min(n1, BSIZE - (off % BSIZE));
35424111398Skaashoek     memmove(dst, bp->data + (off % BSIZE), n1);
355c59361f1Srtm     n -= n1;
356c59361f1Srtm     off += n1;
357c59361f1Srtm     dst += n1;
358c59361f1Srtm     brelse(bp);
359c59361f1Srtm   }
360c59361f1Srtm 
361c59361f1Srtm   return target - n;
362c59361f1Srtm }
363c59361f1Srtm 
3641be76685Skaashoek static int
365ea2909b6Skaashoek newblock(struct inode *ip, uint lbn)
366ea2909b6Skaashoek {
367ea2909b6Skaashoek   struct buf *inbp;
368ea2909b6Skaashoek   uint *inaddrs;
369ea2909b6Skaashoek   uint b;
370ea2909b6Skaashoek 
371ea2909b6Skaashoek   if(lbn < NDIRECT) {
372ea2909b6Skaashoek     if(ip->addrs[lbn] == 0) {
373ea2909b6Skaashoek       b = balloc(ip->dev);
37448b82470Srsc       if(b <= 0)
37548b82470Srsc         return -1;
376ea2909b6Skaashoek       ip->addrs[lbn] = b;
377ea2909b6Skaashoek     }
378ea2909b6Skaashoek   } else {
379ea2909b6Skaashoek     if(ip->addrs[INDIRECT] == 0) {
380ea2909b6Skaashoek       b = balloc(ip->dev);
38148b82470Srsc       if(b <= 0)
38248b82470Srsc         return -1;
383ea2909b6Skaashoek       ip->addrs[INDIRECT] = b;
384ea2909b6Skaashoek     }
3851be76685Skaashoek     inbp = bread(ip->dev, ip->addrs[INDIRECT]);
386ea2909b6Skaashoek     inaddrs = (uint*) inbp->data;
387ea2909b6Skaashoek     if(inaddrs[lbn - NDIRECT] == 0) {
388ea2909b6Skaashoek       b = balloc(ip->dev);
38948b82470Srsc       if(b <= 0)
39048b82470Srsc         return -1;
391ea2909b6Skaashoek       inaddrs[lbn - NDIRECT] = b;
3921be76685Skaashoek       bwrite(inbp, ip->addrs[INDIRECT]);
393ea2909b6Skaashoek     }
394ea2909b6Skaashoek     brelse(inbp);
395ea2909b6Skaashoek   }
396ea2909b6Skaashoek   return 0;
397ea2909b6Skaashoek }
398ea2909b6Skaashoek 
399ea2909b6Skaashoek int
40017a85657Srtm writei(struct inode *ip, char *addr, uint off, uint n)
4016fa5ffb5Skaashoek {
4026fa5ffb5Skaashoek   if(ip->type == T_DEV) {
403*1dca3afbSrsc     if(ip->major < 0 || ip->major >= NDEV || !devsw[ip->major].write)
404939f9edeSkaashoek       return -1;
405*1dca3afbSrsc     return devsw[ip->major].write(ip->minor, addr, n);
406ea2909b6Skaashoek   } else if(ip->type == T_FILE || ip->type == T_DIR) {
40728d9ef04Skaashoek     struct buf *bp;
40828d9ef04Skaashoek     int r = 0;
40928d9ef04Skaashoek     int m;
41028d9ef04Skaashoek     int lbn;
41128d9ef04Skaashoek     while(r < n) {
41228d9ef04Skaashoek       lbn = off / BSIZE;
41348b82470Srsc       if(lbn >= MAXFILE)
41448b82470Srsc         return r;
415ea2909b6Skaashoek       if(newblock(ip, lbn) < 0) {
416ea2909b6Skaashoek         cprintf("newblock failed\n");
417ea2909b6Skaashoek         return r;
41828d9ef04Skaashoek       }
41922bac2cbSkaashoek       m = min(BSIZE - off % BSIZE, n-r);
420ea2909b6Skaashoek       bp = bread(ip->dev, bmap(ip, lbn));
42128d9ef04Skaashoek       memmove(bp->data + off % BSIZE, addr, m);
422ea2909b6Skaashoek       bwrite(bp, bmap(ip, lbn));
42328d9ef04Skaashoek       brelse(bp);
42428d9ef04Skaashoek       r += m;
42528d9ef04Skaashoek       off += m;
42628d9ef04Skaashoek     }
42728d9ef04Skaashoek     if(r > 0) {
42828d9ef04Skaashoek       if(off > ip->size) {
42948b82470Srsc         if(ip->type == T_DIR)
43048b82470Srsc           ip->size = ((off / BSIZE) + 1) * BSIZE;
43148b82470Srsc         else
43248b82470Srsc           ip->size = off;
43328d9ef04Skaashoek       }
43428d9ef04Skaashoek       iupdate(ip);
43528d9ef04Skaashoek     }
43628d9ef04Skaashoek     return r;
4376fa5ffb5Skaashoek   } else {
4382aa4c3bcSrtm     panic("writei: unknown type");
4398a8be1b8Srtm     return 0;
4406fa5ffb5Skaashoek   }
4416fa5ffb5Skaashoek }
4426fa5ffb5Skaashoek 
443211ff0c6Srtm // look up a path name, in one of three modes.
444211ff0c6Srtm // NAMEI_LOOKUP: return locked target inode.
445211ff0c6Srtm // NAMEI_CREATE: return locked parent inode.
4465051da6dSrtm //   return 0 if name does exist.
4475051da6dSrtm //   *ret_last points to last path component (i.e. new file name).
4485051da6dSrtm //   *ret_ip points to the the name that did exist, if it did.
4495051da6dSrtm //   *ret_ip and *ret_last may be zero even if return value is zero.
450211ff0c6Srtm // NAMEI_DELETE: return locked parent inode, offset of dirent in *ret_off.
451211ff0c6Srtm //   return 0 if name doesn't exist.
4529d3fb671Srtm struct inode*
4530cfc7290Srsc namei(char *path, int mode, uint *ret_off,
4540cfc7290Srsc       char **ret_last, struct inode **ret_ip)
4559d3fb671Srtm {
4569d3fb671Srtm   struct inode *dp;
4578787cd01Skaashoek   struct proc *p = curproc[cpu()];
458211ff0c6Srtm   char *cp = path, *cp1;
4599d3fb671Srtm   uint off, dev;
4609d3fb671Srtm   struct buf *bp;
4619d3fb671Srtm   struct dirent *ep;
462211ff0c6Srtm   int i, atend;
4639d3fb671Srtm   unsigned ninum;
4649d3fb671Srtm 
4655051da6dSrtm   if(ret_off)
4665051da6dSrtm     *ret_off = 0xffffffff;
4675051da6dSrtm   if(ret_last)
4685051da6dSrtm     *ret_last = 0;
4695051da6dSrtm   if(ret_ip)
4705051da6dSrtm     *ret_ip = 0;
4715051da6dSrtm 
47248b82470Srsc   if(*cp == '/')
47348b82470Srsc     dp = iget(rootdev, 1);
4748787cd01Skaashoek   else {
4758787cd01Skaashoek     dp = p->cwd;
4768787cd01Skaashoek     iincref(dp);
4778787cd01Skaashoek     ilock(dp);
4788787cd01Skaashoek   }
4799d3fb671Srtm 
4809d3fb671Srtm   while(*cp == '/')
4819d3fb671Srtm     cp++;
4829d3fb671Srtm 
483db8fb62eSrsc   for(;;){
4840633b971Skaashoek     if(*cp == '\0'){
485211ff0c6Srtm       if(mode == NAMEI_LOOKUP)
4869d3fb671Srtm         return dp;
4875051da6dSrtm       if(mode == NAMEI_CREATE && ret_ip){
4885051da6dSrtm         *ret_ip = dp;
4895051da6dSrtm         return 0;
4905051da6dSrtm       }
491211ff0c6Srtm       iput(dp);
492211ff0c6Srtm       return 0;
4930633b971Skaashoek     }
4949d3fb671Srtm 
4959d3fb671Srtm     if(dp->type != T_DIR){
4969d3fb671Srtm       iput(dp);
4979d3fb671Srtm       return 0;
4989d3fb671Srtm     }
4999d3fb671Srtm 
50024111398Skaashoek     for(off = 0; off < dp->size; off += BSIZE){
50124111398Skaashoek       bp = bread(dp->dev, bmap(dp, off / BSIZE));
5029d3fb671Srtm       for(ep = (struct dirent*) bp->data;
50324111398Skaashoek           ep < (struct dirent*) (bp->data + BSIZE);
5049d3fb671Srtm           ep++){
5059d3fb671Srtm         if(ep->inum == 0)
5069d3fb671Srtm           continue;
5079d3fb671Srtm         for(i = 0; i < DIRSIZ && cp[i] != '/' && cp[i]; i++)
5089d3fb671Srtm           if(cp[i] != ep->name[i])
5099d3fb671Srtm             break;
51003c70cc2Srtm         if((cp[i] == '\0' || cp[i] == '/' || i >= DIRSIZ) &&
51103c70cc2Srtm            (i >= DIRSIZ || ep->name[i] == '\0')){
51203c70cc2Srtm           while(cp[i] != '\0' && cp[i] != '/')
51303c70cc2Srtm             i++;
514211ff0c6Srtm           off += (uchar*)ep - bp->data;
5159d3fb671Srtm           ninum = ep->inum;
5169d3fb671Srtm           brelse(bp);
5179d3fb671Srtm           cp += i;
5189d3fb671Srtm           goto found;
5199d3fb671Srtm         }
5209d3fb671Srtm       }
5219d3fb671Srtm       brelse(bp);
5229d3fb671Srtm     }
523211ff0c6Srtm     atend = 1;
524211ff0c6Srtm     for(cp1 = cp; *cp1; cp1++)
525211ff0c6Srtm       if(*cp1 == '/')
526211ff0c6Srtm         atend = 0;
5275051da6dSrtm     if(mode == NAMEI_CREATE && atend){
5285051da6dSrtm       if(*cp == '\0'){
5295051da6dSrtm         iput(dp);
5305051da6dSrtm         return 0;
5315051da6dSrtm       }
5325051da6dSrtm       *ret_last = cp;
533211ff0c6Srtm       return dp;
5345051da6dSrtm     }
535211ff0c6Srtm 
5369d3fb671Srtm     iput(dp);
5379d3fb671Srtm     return 0;
5389d3fb671Srtm 
5399d3fb671Srtm   found:
540211ff0c6Srtm     if(mode == NAMEI_DELETE && *cp == '\0'){
541211ff0c6Srtm       *ret_off = off;
542211ff0c6Srtm       return dp;
543211ff0c6Srtm     }
5449d3fb671Srtm     dev = dp->dev;
5459d3fb671Srtm     iput(dp);
5469d3fb671Srtm     dp = iget(dev, ninum);
5477ce01cf9Srtm     if(dp->type == 0 || dp->nlink < 1)
5487ce01cf9Srtm       panic("namei");
5499d3fb671Srtm     while(*cp == '/')
5509d3fb671Srtm       cp++;
5519d3fb671Srtm   }
5529d3fb671Srtm }
553e8d11c2eSkaashoek 
5549e5970d5Srtm void
5559e5970d5Srtm wdir(struct inode *dp, char *name, uint ino)
5569e5970d5Srtm {
5579e5970d5Srtm   uint off;
558e4bcd2a3Srtm   struct dirent de;
5599e5970d5Srtm   int i;
5609e5970d5Srtm 
561e4bcd2a3Srtm   for(off = 0; off < dp->size; off += sizeof(de)){
562e4bcd2a3Srtm     if(readi(dp, (char*) &de, off, sizeof(de)) != sizeof(de))
563e4bcd2a3Srtm       panic("wdir read");
564e4bcd2a3Srtm     if(de.inum == 0)
565e4bcd2a3Srtm       break;
566e4bcd2a3Srtm   }
567211ff0c6Srtm 
568e4bcd2a3Srtm   de.inum = ino;
5692aa4c3bcSrtm   for(i = 0; i < DIRSIZ && name[i]; i++)
570e4bcd2a3Srtm     de.name[i] = name[i];
5719e5970d5Srtm   for( ; i < DIRSIZ; i++)
572e4bcd2a3Srtm     de.name[i] = '\0';
573e4bcd2a3Srtm 
574e4bcd2a3Srtm   if(writei(dp, (char*) &de, off, sizeof(de)) != sizeof(de))
575e4bcd2a3Srtm     panic("wdir write");
5769e5970d5Srtm }
5779e5970d5Srtm 
578e8d11c2eSkaashoek struct inode*
5790633b971Skaashoek mknod(char *cp, short type, short major, short minor)
580e8d11c2eSkaashoek {
5810633b971Skaashoek   struct inode *ip, *dp;
5825051da6dSrtm   char *last;
583e8d11c2eSkaashoek 
5845051da6dSrtm   if((dp = namei(cp, NAMEI_CREATE, 0, &last, 0)) == 0)
5850633b971Skaashoek     return 0;
586211ff0c6Srtm 
5875051da6dSrtm   ip = mknod1(dp, last, type, major, minor);
5885051da6dSrtm 
5895051da6dSrtm   iput(dp);
5905051da6dSrtm 
5915051da6dSrtm   return ip;
5925051da6dSrtm }
5935051da6dSrtm 
5945051da6dSrtm struct inode*
5955051da6dSrtm mknod1(struct inode *dp, char *name, short type, short major, short minor)
5965051da6dSrtm {
5975051da6dSrtm   struct inode *ip;
5985051da6dSrtm 
599e8d11c2eSkaashoek   ip = ialloc(dp->dev, type);
6002aa4c3bcSrtm   if(ip == 0)
6010633b971Skaashoek     return 0;
602e8d11c2eSkaashoek   ip->major = major;
603e8d11c2eSkaashoek   ip->minor = minor;
6046c0e444fSkaashoek   ip->size = 0;
6057ce01cf9Srtm   ip->nlink = 1;
6066c0e444fSkaashoek 
6076c0e444fSkaashoek   iupdate(ip);  // write new inode to disk
608e8d11c2eSkaashoek 
6095051da6dSrtm   wdir(dp, name, ip->inum);
6105051da6dSrtm 
611e8d11c2eSkaashoek   return ip;
612e8d11c2eSkaashoek }
61324437cd5Skaashoek 
61424437cd5Skaashoek int
61524437cd5Skaashoek unlink(char *cp)
61624437cd5Skaashoek {
617211ff0c6Srtm   struct inode *ip, *dp;
618211ff0c6Srtm   struct dirent de;
61917e3cf15Srtm   uint off, inum, dev;
62024437cd5Skaashoek 
6215051da6dSrtm   dp = namei(cp, NAMEI_DELETE, &off, 0, 0);
6225051da6dSrtm   if(dp == 0)
62324437cd5Skaashoek     return -1;
62424437cd5Skaashoek 
62517e3cf15Srtm   dev = dp->dev;
62617e3cf15Srtm 
62717e3cf15Srtm   if(readi(dp, (char*)&de, off, sizeof(de)) != sizeof(de) || de.inum == 0)
628211ff0c6Srtm     panic("unlink no entry");
62917e3cf15Srtm 
630211ff0c6Srtm   inum = de.inum;
63124437cd5Skaashoek 
632211ff0c6Srtm   memset(&de, 0, sizeof(de));
633211ff0c6Srtm   if(writei(dp, (char*)&de, off, sizeof(de)) != sizeof(de))
634211ff0c6Srtm     panic("unlink dir write");
63524437cd5Skaashoek 
63624437cd5Skaashoek   iupdate(dp);
63724437cd5Skaashoek   iput(dp);
638211ff0c6Srtm 
63917e3cf15Srtm   ip = iget(dev, inum);
640211ff0c6Srtm 
641bcfb84b6Srtm   if(ip->nlink < 1)
642bcfb84b6Srtm     panic("unlink nlink < 1");
643bcfb84b6Srtm 
644211ff0c6Srtm   ip->nlink--;
645211ff0c6Srtm 
646211ff0c6Srtm   iupdate(ip);
64722bac2cbSkaashoek   iput(ip);
648211ff0c6Srtm 
64924437cd5Skaashoek   return 0;
65024437cd5Skaashoek }
6519e5970d5Srtm 
6529e5970d5Srtm int
6539e5970d5Srtm link(char *name1, char *name2)
6549e5970d5Srtm {
655211ff0c6Srtm   struct inode *ip, *dp;
6565051da6dSrtm   char *last;
6579e5970d5Srtm 
6585051da6dSrtm   if((ip = namei(name1, NAMEI_LOOKUP, 0, 0, 0)) == 0)
6599e5970d5Srtm     return -1;
660211ff0c6Srtm   if(ip->type == T_DIR){
661211ff0c6Srtm     iput(ip);
662211ff0c6Srtm     return -1;
663211ff0c6Srtm   }
6649e5970d5Srtm 
665211ff0c6Srtm   iunlock(ip);
666211ff0c6Srtm 
6675051da6dSrtm   if((dp = namei(name2, NAMEI_CREATE, 0, &last, 0)) == 0) {
668211ff0c6Srtm     idecref(ip);
669211ff0c6Srtm     return -1;
670211ff0c6Srtm   }
671211ff0c6Srtm   if(dp->dev != ip->dev){
672211ff0c6Srtm     idecref(ip);
673211ff0c6Srtm     iput(dp);
674211ff0c6Srtm     return -1;
675211ff0c6Srtm   }
676211ff0c6Srtm 
677211ff0c6Srtm   ilock(ip);
6789e5970d5Srtm   ip->nlink += 1;
6799e5970d5Srtm   iupdate(ip);
6809e5970d5Srtm 
6815051da6dSrtm   wdir(dp, last, ip->inum);
6829e5970d5Srtm   iput(dp);
6839e5970d5Srtm   iput(ip);
6849e5970d5Srtm 
6859e5970d5Srtm   return 0;
6869e5970d5Srtm }
687