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 27*2aa4c3bcSrtm /* 28*2aa4c3bcSrtm * allocate a disk block 29*2aa4c3bcSrtm */ 3024111398Skaashoek static uint 3124111398Skaashoek balloc(uint dev) 3224111398Skaashoek { 3324111398Skaashoek int b; 3424111398Skaashoek struct buf *bp; 3524111398Skaashoek struct superblock *sb; 3628d9ef04Skaashoek int bi = 0; 3724111398Skaashoek int size; 3824111398Skaashoek int ninodes; 3924111398Skaashoek uchar m; 4024111398Skaashoek 4124111398Skaashoek bp = bread(dev, 1); 4224111398Skaashoek sb = (struct superblock *) bp->data; 4324111398Skaashoek size = sb->size; 4424111398Skaashoek ninodes = sb->ninodes; 4524111398Skaashoek 4624111398Skaashoek for (b = 0; b < size; b++) { 4724111398Skaashoek if (b % BPB == 0) { 4824111398Skaashoek brelse(bp); 4924111398Skaashoek bp = bread(dev, BBLOCK(b, ninodes)); 5024111398Skaashoek } 5124111398Skaashoek bi = b % BPB; 5224111398Skaashoek m = 0x1 << (bi % 8); 5324111398Skaashoek if ((bp->data[bi/8] & m) == 0) { // is block free? 5424111398Skaashoek break; 5524111398Skaashoek } 5624111398Skaashoek } 5724111398Skaashoek if (b >= size) 58*2aa4c3bcSrtm panic("balloc: out of blocks"); 5924111398Skaashoek 6024111398Skaashoek bp->data[bi/8] |= 0x1 << (bi % 8); 6105e97551Srtm bwrite (bp, BBLOCK(b, ninodes)); // mark it allocated on disk 6228d9ef04Skaashoek brelse(bp); 6324111398Skaashoek return b; 6424111398Skaashoek } 6524111398Skaashoek 6628d9ef04Skaashoek static void 6728d9ef04Skaashoek bfree(int dev, uint b) 6828d9ef04Skaashoek { 6928d9ef04Skaashoek struct buf *bp; 7028d9ef04Skaashoek struct superblock *sb; 7128d9ef04Skaashoek int bi; 7228d9ef04Skaashoek int ninodes; 7328d9ef04Skaashoek uchar m; 7428d9ef04Skaashoek 7528d9ef04Skaashoek bp = bread(dev, 1); 7628d9ef04Skaashoek sb = (struct superblock *) bp->data; 7728d9ef04Skaashoek ninodes = sb->ninodes; 7828d9ef04Skaashoek brelse(bp); 7928d9ef04Skaashoek 80c372e8dcSkaashoek bp = bread(dev, b); 81c372e8dcSkaashoek memset(bp->data, 0, BSIZE); 82c372e8dcSkaashoek bwrite(bp, b); 83c372e8dcSkaashoek brelse(bp); 84c372e8dcSkaashoek 8528d9ef04Skaashoek bp = bread(dev, BBLOCK(b, ninodes)); 8628d9ef04Skaashoek bi = b % BPB; 8728d9ef04Skaashoek m = ~(0x1 << (bi %8)); 8828d9ef04Skaashoek bp->data[bi/8] &= m; 8905e97551Srtm bwrite (bp, BBLOCK(b, ninodes)); // mark it free on disk 9028d9ef04Skaashoek brelse(bp); 9128d9ef04Skaashoek } 9224111398Skaashoek 93*2aa4c3bcSrtm /* 94*2aa4c3bcSrtm * fetch an inode, from the in-core table if it's already 95*2aa4c3bcSrtm * in use, otherwise read from the disk. 96*2aa4c3bcSrtm * returns an inode with busy set and incremented reference count. 97*2aa4c3bcSrtm */ 9811a9947fSrtm struct inode * 9911a9947fSrtm iget(uint dev, uint inum) 10011a9947fSrtm { 10117e3cf15Srtm struct inode *ip, *nip; 10211a9947fSrtm struct dinode *dip; 10311a9947fSrtm struct buf *bp; 10411a9947fSrtm 10511a9947fSrtm acquire(&inode_table_lock); 10611a9947fSrtm 10711a9947fSrtm loop: 10817e3cf15Srtm nip = 0; 10911a9947fSrtm for(ip = &inode[0]; ip < &inode[NINODE]; ip++){ 11011a9947fSrtm if(ip->count > 0 && ip->dev == dev && ip->inum == inum){ 11111a9947fSrtm if(ip->busy){ 11211a9947fSrtm sleep(ip, &inode_table_lock); 11311a9947fSrtm goto loop; 11411a9947fSrtm } 11511a9947fSrtm ip->count++; 11617a85657Srtm ip->busy = 1; 11711a9947fSrtm release(&inode_table_lock); 11811a9947fSrtm return ip; 11911a9947fSrtm } 12011a9947fSrtm if(nip == 0 && ip->count == 0) 12111a9947fSrtm nip = ip; 12211a9947fSrtm } 12311a9947fSrtm 12411a9947fSrtm if(nip == 0) 12511a9947fSrtm panic("out of inodes"); 12611a9947fSrtm 12711a9947fSrtm nip->dev = dev; 12811a9947fSrtm nip->inum = inum; 12911a9947fSrtm nip->count = 1; 13011a9947fSrtm nip->busy = 1; 13111a9947fSrtm 13211a9947fSrtm release(&inode_table_lock); 13311a9947fSrtm 13424111398Skaashoek bp = bread(dev, IBLOCK(inum)); 13511a9947fSrtm dip = &((struct dinode *)(bp->data))[inum % IPB]; 13611a9947fSrtm nip->type = dip->type; 137e8d11c2eSkaashoek nip->major = dip->major; 138e8d11c2eSkaashoek nip->minor = dip->minor; 13911a9947fSrtm nip->nlink = dip->nlink; 14011a9947fSrtm nip->size = dip->size; 14111a9947fSrtm memmove(nip->addrs, dip->addrs, sizeof(nip->addrs)); 14211a9947fSrtm brelse(bp); 14311a9947fSrtm 14411a9947fSrtm return nip; 14511a9947fSrtm } 14611a9947fSrtm 14728d9ef04Skaashoek void 14828d9ef04Skaashoek iupdate (struct inode *ip) 14928d9ef04Skaashoek { 15028d9ef04Skaashoek struct buf *bp; 15128d9ef04Skaashoek struct dinode *dip; 15228d9ef04Skaashoek 15328d9ef04Skaashoek bp = bread(ip->dev, IBLOCK(ip->inum)); 15428d9ef04Skaashoek dip = &((struct dinode *)(bp->data))[ip->inum % IPB]; 15528d9ef04Skaashoek dip->type = ip->type; 15628d9ef04Skaashoek dip->major = ip->major; 15728d9ef04Skaashoek dip->minor = ip->minor; 15828d9ef04Skaashoek dip->nlink = ip->nlink; 15928d9ef04Skaashoek dip->size = ip->size; 16028d9ef04Skaashoek memmove(dip->addrs, ip->addrs, sizeof(ip->addrs)); 16105e97551Srtm bwrite (bp, IBLOCK(ip->inum)); // mark it allocated on the disk 16228d9ef04Skaashoek brelse(bp); 16328d9ef04Skaashoek } 16428d9ef04Skaashoek 165e8d11c2eSkaashoek struct inode * 166e8d11c2eSkaashoek ialloc(uint dev, short type) 167e8d11c2eSkaashoek { 168e8d11c2eSkaashoek struct inode *ip; 169e8d11c2eSkaashoek struct dinode *dip = 0; 170e8d11c2eSkaashoek struct superblock *sb; 171e8d11c2eSkaashoek int ninodes; 172e8d11c2eSkaashoek int inum; 173e8d11c2eSkaashoek struct buf *bp; 174e8d11c2eSkaashoek 175e8d11c2eSkaashoek bp = bread(dev, 1); 17624111398Skaashoek sb = (struct superblock *) bp->data; 177e8d11c2eSkaashoek ninodes = sb->ninodes; 178e8d11c2eSkaashoek brelse(bp); 179e8d11c2eSkaashoek 180e8d11c2eSkaashoek for (inum = 1; inum < ninodes; inum++) { // loop over inode blocks 18124111398Skaashoek bp = bread(dev, IBLOCK(inum)); 182e8d11c2eSkaashoek dip = &((struct dinode *)(bp->data))[inum % IPB]; 183e8d11c2eSkaashoek if (dip->type == 0) { // a free inode 184e8d11c2eSkaashoek break; 185e8d11c2eSkaashoek } 186e8d11c2eSkaashoek brelse(bp); 187e8d11c2eSkaashoek } 188e8d11c2eSkaashoek 18917e3cf15Srtm if (inum >= ninodes) 190*2aa4c3bcSrtm panic ("ialloc: no inodes left"); 191e8d11c2eSkaashoek 192*2aa4c3bcSrtm memset(dip, 0, sizeof(*dip)); 193e8d11c2eSkaashoek dip->type = type; 19405e97551Srtm bwrite (bp, IBLOCK(inum)); // mark it allocated on the disk 195e8d11c2eSkaashoek brelse(bp); 196e8d11c2eSkaashoek ip = iget (dev, inum); 197e8d11c2eSkaashoek return ip; 198e8d11c2eSkaashoek } 199e8d11c2eSkaashoek 20028d9ef04Skaashoek static void 20124437cd5Skaashoek ifree(struct inode *ip) 202e8d11c2eSkaashoek { 20328d9ef04Skaashoek ip->type = 0; 20428d9ef04Skaashoek iupdate(ip); 205e8d11c2eSkaashoek } 206e8d11c2eSkaashoek 20711a9947fSrtm void 2089d3fb671Srtm ilock(struct inode *ip) 2099d3fb671Srtm { 2109d3fb671Srtm if(ip->count < 1) 2119d3fb671Srtm panic("ilock"); 2129d3fb671Srtm 2139d3fb671Srtm acquire(&inode_table_lock); 2149d3fb671Srtm 2159d3fb671Srtm while(ip->busy) 2169d3fb671Srtm sleep(ip, &inode_table_lock); 2179d3fb671Srtm ip->busy = 1; 2189d3fb671Srtm 2199d3fb671Srtm release(&inode_table_lock); 2209d3fb671Srtm } 2219d3fb671Srtm 2229d3fb671Srtm // caller is holding onto a reference to this inode, but no 2239d3fb671Srtm // longer needs to examine or change it, so clear ip->busy. 2249d3fb671Srtm void 2259d3fb671Srtm iunlock(struct inode *ip) 2269d3fb671Srtm { 22717e3cf15Srtm if(ip->busy != 1 || ip->count < 1) 2289d3fb671Srtm panic("iunlock"); 2299d3fb671Srtm 2309d3fb671Srtm acquire(&inode_table_lock); 2319d3fb671Srtm 2329d3fb671Srtm ip->busy = 0; 2339d3fb671Srtm wakeup(ip); 2349d3fb671Srtm 2359d3fb671Srtm release(&inode_table_lock); 2369d3fb671Srtm } 2379d3fb671Srtm 23822bac2cbSkaashoek uint 23922bac2cbSkaashoek bmap(struct inode *ip, uint bn) 24022bac2cbSkaashoek { 24122bac2cbSkaashoek unsigned x; 242ea2909b6Skaashoek uint *a; 243ea2909b6Skaashoek struct buf *inbp; 24422bac2cbSkaashoek 245ea2909b6Skaashoek if(bn >= MAXFILE) 24622bac2cbSkaashoek panic("bmap 1"); 247ea2909b6Skaashoek if (bn < NDIRECT) { 24822bac2cbSkaashoek x = ip->addrs[bn]; 24922bac2cbSkaashoek if (x == 0) 25022bac2cbSkaashoek panic("bmap 2"); 251ea2909b6Skaashoek } else { 2525051da6dSrtm if(ip->addrs[INDIRECT] == 0) 2535051da6dSrtm panic("bmap 3"); 2541be76685Skaashoek inbp = bread(ip->dev, ip->addrs[INDIRECT]); 255ea2909b6Skaashoek a = (uint *) inbp->data; 256ea2909b6Skaashoek x = a[bn - NDIRECT]; 257ea2909b6Skaashoek brelse(inbp); 258ea2909b6Skaashoek if (x == 0) 2595051da6dSrtm panic("bmap 4"); 260ea2909b6Skaashoek } 26122bac2cbSkaashoek return x; 26222bac2cbSkaashoek } 26322bac2cbSkaashoek 26422bac2cbSkaashoek void 265*2aa4c3bcSrtm itrunc(struct inode *ip) 26622bac2cbSkaashoek { 267ea2909b6Skaashoek int i, j; 2681be76685Skaashoek struct buf *inbp; 26922bac2cbSkaashoek 270ea2909b6Skaashoek for (i = 0; i < NADDRS; i++) { 27122bac2cbSkaashoek if (ip->addrs[i] != 0) { 272ea2909b6Skaashoek if (i == INDIRECT) { 2731be76685Skaashoek inbp = bread(ip->dev, ip->addrs[INDIRECT]); 2741be76685Skaashoek uint *a = (uint *) inbp->data; 275bcfb84b6Srtm for (j = 0; j < NINDIRECT; j++) { 276ea2909b6Skaashoek if (a[j] != 0) { 277ea2909b6Skaashoek bfree(ip->dev, a[j]); 278ea2909b6Skaashoek a[j] = 0; 279ea2909b6Skaashoek } 280ea2909b6Skaashoek } 2811be76685Skaashoek brelse(inbp); 282ea2909b6Skaashoek } 28322bac2cbSkaashoek bfree(ip->dev, ip->addrs[i]); 28422bac2cbSkaashoek ip->addrs[i] = 0; 28522bac2cbSkaashoek } 28622bac2cbSkaashoek } 28722bac2cbSkaashoek ip->size = 0; 28822bac2cbSkaashoek iupdate(ip); 28922bac2cbSkaashoek } 29022bac2cbSkaashoek 2919d3fb671Srtm // caller is releasing a reference to this inode. 2929d3fb671Srtm // you must have the inode lock. 2939d3fb671Srtm void 29411a9947fSrtm iput(struct inode *ip) 29511a9947fSrtm { 2969d3fb671Srtm if(ip->count < 1 || ip->busy != 1) 2979d3fb671Srtm panic("iput"); 2989d3fb671Srtm 299*2aa4c3bcSrtm if ((ip->count == 1) && (ip->nlink == 0)) { 300*2aa4c3bcSrtm itrunc(ip); 301*2aa4c3bcSrtm ifree(ip); 302*2aa4c3bcSrtm } 30322bac2cbSkaashoek 30411a9947fSrtm acquire(&inode_table_lock); 30511a9947fSrtm 30611a9947fSrtm ip->count -= 1; 30711a9947fSrtm ip->busy = 0; 30811a9947fSrtm wakeup(ip); 30911a9947fSrtm 31011a9947fSrtm release(&inode_table_lock); 31111a9947fSrtm } 3129d3fb671Srtm 3139d3fb671Srtm void 31432630628Srtm idecref(struct inode *ip) 3159d3fb671Srtm { 316211ff0c6Srtm ilock(ip); 317211ff0c6Srtm iput(ip); 3189d3fb671Srtm } 3199d3fb671Srtm 3201f544842Skaashoek void 321e958c538Skaashoek iincref(struct inode *ip) 322e958c538Skaashoek { 323e958c538Skaashoek ilock(ip); 324e958c538Skaashoek ip->count++; 325e958c538Skaashoek iunlock(ip); 326e958c538Skaashoek } 327e958c538Skaashoek 328e958c538Skaashoek void 3291f544842Skaashoek stati(struct inode *ip, struct stat *st) 3301f544842Skaashoek { 3311f544842Skaashoek st->st_dev = ip->dev; 3321f544842Skaashoek st->st_ino = ip->inum; 3331f544842Skaashoek st->st_type = ip->type; 3341f544842Skaashoek st->st_nlink = ip->nlink; 3351f544842Skaashoek st->st_size = ip->size; 3361f544842Skaashoek } 3371f544842Skaashoek 33822bac2cbSkaashoek #define min(a, b) ((a) < (b) ? (a) : (b)) 33922bac2cbSkaashoek 340c59361f1Srtm int 34117a85657Srtm readi(struct inode *ip, char *dst, uint off, uint n) 342c59361f1Srtm { 343c59361f1Srtm uint target = n, n1; 344c59361f1Srtm struct buf *bp; 345c59361f1Srtm 346939f9edeSkaashoek if (ip->type == T_DEV) { 347939f9edeSkaashoek if (ip->major < 0 || ip->major >= NDEV || !devsw[ip->major].d_read) 348939f9edeSkaashoek return -1; 34917a85657Srtm return devsw[ip->major].d_read (ip->minor, dst, n); 350939f9edeSkaashoek } 351939f9edeSkaashoek 352c59361f1Srtm while(n > 0 && off < ip->size){ 35324111398Skaashoek bp = bread(ip->dev, bmap(ip, off / BSIZE)); 354c59361f1Srtm n1 = min(n, ip->size - off); 35524111398Skaashoek n1 = min(n1, BSIZE - (off % BSIZE)); 35624111398Skaashoek memmove(dst, bp->data + (off % BSIZE), n1); 357c59361f1Srtm n -= n1; 358c59361f1Srtm off += n1; 359c59361f1Srtm dst += n1; 360c59361f1Srtm brelse(bp); 361c59361f1Srtm } 362c59361f1Srtm 363c59361f1Srtm return target - n; 364c59361f1Srtm } 365c59361f1Srtm 3661be76685Skaashoek static int 367ea2909b6Skaashoek newblock(struct inode *ip, uint lbn) 368ea2909b6Skaashoek { 369ea2909b6Skaashoek struct buf *inbp; 370ea2909b6Skaashoek uint *inaddrs; 371ea2909b6Skaashoek uint b; 372ea2909b6Skaashoek 373ea2909b6Skaashoek if (lbn < NDIRECT) { 374ea2909b6Skaashoek if (ip->addrs[lbn] == 0) { 375ea2909b6Skaashoek b = balloc(ip->dev); 376ea2909b6Skaashoek if (b <= 0) return -1; 377ea2909b6Skaashoek ip->addrs[lbn] = b; 378ea2909b6Skaashoek } 379ea2909b6Skaashoek } else { 380ea2909b6Skaashoek if (ip->addrs[INDIRECT] == 0) { 381ea2909b6Skaashoek b = balloc(ip->dev); 382ea2909b6Skaashoek if (b <= 0) 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); 389ea2909b6Skaashoek if (b <= 0) return -1; 390ea2909b6Skaashoek inaddrs[lbn - NDIRECT] = b; 3911be76685Skaashoek bwrite(inbp, ip->addrs[INDIRECT]); 392ea2909b6Skaashoek } 393ea2909b6Skaashoek brelse(inbp); 394ea2909b6Skaashoek } 395ea2909b6Skaashoek return 0; 396ea2909b6Skaashoek } 397ea2909b6Skaashoek 398ea2909b6Skaashoek int 39917a85657Srtm writei(struct inode *ip, char *addr, uint off, uint n) 4006fa5ffb5Skaashoek { 4016fa5ffb5Skaashoek if (ip->type == T_DEV) { 402939f9edeSkaashoek if (ip->major < 0 || ip->major >= NDEV || !devsw[ip->major].d_write) 403939f9edeSkaashoek return -1; 4046fa5ffb5Skaashoek return devsw[ip->major].d_write (ip->minor, addr, n); 405ea2909b6Skaashoek } else if (ip->type == T_FILE || ip->type == T_DIR) { 40628d9ef04Skaashoek struct buf *bp; 40728d9ef04Skaashoek int r = 0; 40828d9ef04Skaashoek int m; 40928d9ef04Skaashoek int lbn; 41028d9ef04Skaashoek while (r < n) { 41128d9ef04Skaashoek lbn = off / BSIZE; 412ea2909b6Skaashoek if (lbn >= MAXFILE) return r; 413ea2909b6Skaashoek if (newblock(ip, lbn) < 0) { 414ea2909b6Skaashoek cprintf("newblock failed\n"); 415ea2909b6Skaashoek return r; 41628d9ef04Skaashoek } 41722bac2cbSkaashoek m = min(BSIZE - off % BSIZE, n-r); 418ea2909b6Skaashoek bp = bread(ip->dev, bmap(ip, lbn)); 41928d9ef04Skaashoek memmove (bp->data + off % BSIZE, addr, m); 420ea2909b6Skaashoek bwrite (bp, bmap(ip, lbn)); 42128d9ef04Skaashoek brelse (bp); 42228d9ef04Skaashoek r += m; 42328d9ef04Skaashoek off += m; 42428d9ef04Skaashoek } 42528d9ef04Skaashoek if (r > 0) { 42628d9ef04Skaashoek if (off > ip->size) { 427bdb66433Skaashoek if (ip->type == T_DIR) ip->size = ((off / BSIZE) + 1) * BSIZE; 428bdb66433Skaashoek else ip->size = off; 42928d9ef04Skaashoek } 43028d9ef04Skaashoek iupdate(ip); 43128d9ef04Skaashoek } 43228d9ef04Skaashoek return r; 4336fa5ffb5Skaashoek } else { 434*2aa4c3bcSrtm panic ("writei: unknown type"); 4358a8be1b8Srtm return 0; 4366fa5ffb5Skaashoek } 4376fa5ffb5Skaashoek } 4386fa5ffb5Skaashoek 439211ff0c6Srtm // look up a path name, in one of three modes. 440211ff0c6Srtm // NAMEI_LOOKUP: return locked target inode. 441211ff0c6Srtm // NAMEI_CREATE: return locked parent inode. 4425051da6dSrtm // return 0 if name does exist. 4435051da6dSrtm // *ret_last points to last path component (i.e. new file name). 4445051da6dSrtm // *ret_ip points to the the name that did exist, if it did. 4455051da6dSrtm // *ret_ip and *ret_last may be zero even if return value is zero. 446211ff0c6Srtm // NAMEI_DELETE: return locked parent inode, offset of dirent in *ret_off. 447211ff0c6Srtm // return 0 if name doesn't exist. 4489d3fb671Srtm struct inode * 4495051da6dSrtm namei(char *path, int mode, uint *ret_off, char **ret_last, struct inode **ret_ip) 4509d3fb671Srtm { 4519d3fb671Srtm struct inode *dp; 4528787cd01Skaashoek struct proc *p = curproc[cpu()]; 453211ff0c6Srtm char *cp = path, *cp1; 4549d3fb671Srtm uint off, dev; 4559d3fb671Srtm struct buf *bp; 4569d3fb671Srtm struct dirent *ep; 457211ff0c6Srtm int i, atend; 4589d3fb671Srtm unsigned ninum; 4599d3fb671Srtm 4605051da6dSrtm if(ret_off) 4615051da6dSrtm *ret_off = 0xffffffff; 4625051da6dSrtm if(ret_last) 4635051da6dSrtm *ret_last = 0; 4645051da6dSrtm if(ret_ip) 4655051da6dSrtm *ret_ip = 0; 4665051da6dSrtm 4678787cd01Skaashoek if (*cp == '/') dp = iget(rootdev, 1); 4688787cd01Skaashoek else { 4698787cd01Skaashoek dp = p->cwd; 4708787cd01Skaashoek iincref(dp); 4718787cd01Skaashoek ilock(dp); 4728787cd01Skaashoek } 4739d3fb671Srtm 4749d3fb671Srtm while(*cp == '/') 4759d3fb671Srtm cp++; 4769d3fb671Srtm 4779d3fb671Srtm while(1){ 4780633b971Skaashoek if(*cp == '\0'){ 479211ff0c6Srtm if(mode == NAMEI_LOOKUP) 4809d3fb671Srtm return dp; 4815051da6dSrtm if(mode == NAMEI_CREATE && ret_ip){ 4825051da6dSrtm *ret_ip = dp; 4835051da6dSrtm return 0; 4845051da6dSrtm } 485211ff0c6Srtm iput(dp); 486211ff0c6Srtm return 0; 4870633b971Skaashoek } 4889d3fb671Srtm 4899d3fb671Srtm if(dp->type != T_DIR){ 4909d3fb671Srtm iput(dp); 4919d3fb671Srtm return 0; 4929d3fb671Srtm } 4939d3fb671Srtm 49424111398Skaashoek for(off = 0; off < dp->size; off += BSIZE){ 49524111398Skaashoek bp = bread(dp->dev, bmap(dp, off / BSIZE)); 4969d3fb671Srtm for(ep = (struct dirent *) bp->data; 49724111398Skaashoek ep < (struct dirent *) (bp->data + BSIZE); 4989d3fb671Srtm ep++){ 4999d3fb671Srtm if(ep->inum == 0) 5009d3fb671Srtm continue; 5019d3fb671Srtm for(i = 0; i < DIRSIZ && cp[i] != '/' && cp[i]; i++) 5029d3fb671Srtm if(cp[i] != ep->name[i]) 5039d3fb671Srtm break; 50403c70cc2Srtm if((cp[i] == '\0' || cp[i] == '/' || i >= DIRSIZ) && 50503c70cc2Srtm (i >= DIRSIZ || ep->name[i] == '\0')){ 50603c70cc2Srtm while(cp[i] != '\0' && cp[i] != '/') 50703c70cc2Srtm i++; 508211ff0c6Srtm off += (uchar*)ep - bp->data; 5099d3fb671Srtm ninum = ep->inum; 5109d3fb671Srtm brelse(bp); 5119d3fb671Srtm cp += i; 5129d3fb671Srtm goto found; 5139d3fb671Srtm } 5149d3fb671Srtm } 5159d3fb671Srtm brelse(bp); 5169d3fb671Srtm } 517211ff0c6Srtm atend = 1; 518211ff0c6Srtm for(cp1 = cp; *cp1; cp1++) 519211ff0c6Srtm if(*cp1 == '/') 520211ff0c6Srtm atend = 0; 5215051da6dSrtm if(mode == NAMEI_CREATE && atend){ 5225051da6dSrtm if(*cp == '\0'){ 5235051da6dSrtm iput(dp); 5245051da6dSrtm return 0; 5255051da6dSrtm } 5265051da6dSrtm *ret_last = cp; 527211ff0c6Srtm return dp; 5285051da6dSrtm } 529211ff0c6Srtm 5309d3fb671Srtm iput(dp); 5319d3fb671Srtm return 0; 5329d3fb671Srtm 5339d3fb671Srtm found: 534211ff0c6Srtm if(mode == NAMEI_DELETE && *cp == '\0'){ 535211ff0c6Srtm *ret_off = off; 536211ff0c6Srtm return dp; 537211ff0c6Srtm } 5389d3fb671Srtm dev = dp->dev; 5399d3fb671Srtm iput(dp); 5409d3fb671Srtm dp = iget(dev, ninum); 5417ce01cf9Srtm if(dp->type == 0 || dp->nlink < 1) 5427ce01cf9Srtm panic("namei"); 5439d3fb671Srtm while(*cp == '/') 5449d3fb671Srtm cp++; 5459d3fb671Srtm } 5469d3fb671Srtm } 547e8d11c2eSkaashoek 5489e5970d5Srtm void 5499e5970d5Srtm wdir(struct inode *dp, char *name, uint ino) 5509e5970d5Srtm { 5519e5970d5Srtm uint off; 552e4bcd2a3Srtm struct dirent de; 5539e5970d5Srtm int i; 5549e5970d5Srtm 555e4bcd2a3Srtm for(off = 0; off < dp->size; off += sizeof(de)){ 556e4bcd2a3Srtm if(readi(dp, (char *) &de, off, sizeof(de)) != sizeof(de)) 557e4bcd2a3Srtm panic("wdir read"); 558e4bcd2a3Srtm if(de.inum == 0) 559e4bcd2a3Srtm break; 560e4bcd2a3Srtm } 561211ff0c6Srtm 562e4bcd2a3Srtm de.inum = ino; 563*2aa4c3bcSrtm for(i = 0; i < DIRSIZ && name[i]; i++) 564e4bcd2a3Srtm de.name[i] = name[i]; 5659e5970d5Srtm for( ; i < DIRSIZ; i++) 566e4bcd2a3Srtm de.name[i] = '\0'; 567e4bcd2a3Srtm 568e4bcd2a3Srtm if(writei(dp, (char *) &de, off, sizeof(de)) != sizeof(de)) 569e4bcd2a3Srtm panic("wdir write"); 5709e5970d5Srtm } 5719e5970d5Srtm 572e8d11c2eSkaashoek struct inode * 5730633b971Skaashoek mknod(char *cp, short type, short major, short minor) 574e8d11c2eSkaashoek { 5750633b971Skaashoek struct inode *ip, *dp; 5765051da6dSrtm char *last; 577e8d11c2eSkaashoek 5785051da6dSrtm if ((dp = namei(cp, NAMEI_CREATE, 0, &last, 0)) == 0) 5790633b971Skaashoek return 0; 580211ff0c6Srtm 5815051da6dSrtm ip = mknod1(dp, last, type, major, minor); 5825051da6dSrtm 5835051da6dSrtm iput(dp); 5845051da6dSrtm 5855051da6dSrtm return ip; 5865051da6dSrtm } 5875051da6dSrtm 5885051da6dSrtm struct inode * 5895051da6dSrtm mknod1(struct inode *dp, char *name, short type, short major, short minor) 5905051da6dSrtm { 5915051da6dSrtm struct inode *ip; 5925051da6dSrtm 593e8d11c2eSkaashoek ip = ialloc(dp->dev, type); 594*2aa4c3bcSrtm if (ip == 0) 5950633b971Skaashoek return 0; 596e8d11c2eSkaashoek ip->major = major; 597e8d11c2eSkaashoek ip->minor = minor; 5986c0e444fSkaashoek ip->size = 0; 5997ce01cf9Srtm ip->nlink = 1; 6006c0e444fSkaashoek 6016c0e444fSkaashoek iupdate (ip); // write new inode to disk 602e8d11c2eSkaashoek 6035051da6dSrtm wdir(dp, name, ip->inum); 6045051da6dSrtm 605e8d11c2eSkaashoek return ip; 606e8d11c2eSkaashoek } 60724437cd5Skaashoek 60824437cd5Skaashoek int 60924437cd5Skaashoek unlink(char *cp) 61024437cd5Skaashoek { 611211ff0c6Srtm struct inode *ip, *dp; 612211ff0c6Srtm struct dirent de; 61317e3cf15Srtm uint off, inum, dev; 61424437cd5Skaashoek 6155051da6dSrtm dp = namei(cp, NAMEI_DELETE, &off, 0, 0); 6165051da6dSrtm if(dp == 0) 61724437cd5Skaashoek return -1; 61824437cd5Skaashoek 61917e3cf15Srtm dev = dp->dev; 62017e3cf15Srtm 62117e3cf15Srtm if(readi(dp, (char*)&de, off, sizeof(de)) != sizeof(de) || de.inum == 0) 622211ff0c6Srtm panic("unlink no entry"); 62317e3cf15Srtm 624211ff0c6Srtm inum = de.inum; 62524437cd5Skaashoek 626211ff0c6Srtm memset(&de, 0, sizeof(de)); 627211ff0c6Srtm if(writei(dp, (char*)&de, off, sizeof(de)) != sizeof(de)) 628211ff0c6Srtm panic("unlink dir write"); 62924437cd5Skaashoek 63024437cd5Skaashoek iupdate(dp); 63124437cd5Skaashoek iput(dp); 632211ff0c6Srtm 63317e3cf15Srtm ip = iget(dev, inum); 634211ff0c6Srtm 635bcfb84b6Srtm if(ip->nlink < 1) 636bcfb84b6Srtm panic("unlink nlink < 1"); 637bcfb84b6Srtm 638211ff0c6Srtm ip->nlink--; 639211ff0c6Srtm 640211ff0c6Srtm iupdate(ip); 64122bac2cbSkaashoek iput(ip); 642211ff0c6Srtm 64324437cd5Skaashoek return 0; 64424437cd5Skaashoek } 6459e5970d5Srtm 6469e5970d5Srtm int 6479e5970d5Srtm link(char *name1, char *name2) 6489e5970d5Srtm { 649211ff0c6Srtm struct inode *ip, *dp; 6505051da6dSrtm char *last; 6519e5970d5Srtm 6525051da6dSrtm if ((ip = namei(name1, NAMEI_LOOKUP, 0, 0, 0)) == 0) 6539e5970d5Srtm return -1; 654211ff0c6Srtm if(ip->type == T_DIR){ 655211ff0c6Srtm iput(ip); 656211ff0c6Srtm return -1; 657211ff0c6Srtm } 6589e5970d5Srtm 659211ff0c6Srtm iunlock(ip); 660211ff0c6Srtm 6615051da6dSrtm if ((dp = namei(name2, NAMEI_CREATE, 0, &last, 0)) == 0) { 662211ff0c6Srtm idecref(ip); 663211ff0c6Srtm return -1; 664211ff0c6Srtm } 665211ff0c6Srtm if(dp->dev != ip->dev){ 666211ff0c6Srtm idecref(ip); 667211ff0c6Srtm iput(dp); 668211ff0c6Srtm return -1; 669211ff0c6Srtm } 670211ff0c6Srtm 671211ff0c6Srtm ilock(ip); 6729e5970d5Srtm ip->nlink += 1; 6739e5970d5Srtm iupdate (ip); 6749e5970d5Srtm 6755051da6dSrtm wdir(dp, last, ip->inum); 6769e5970d5Srtm iput(dp); 6779e5970d5Srtm iput(ip); 6789e5970d5Srtm 6799e5970d5Srtm return 0; 6809e5970d5Srtm } 681