/* * read data from a locked inode. * returns -1 on error. * */ int readi(struct inode *ip, char *buf, uint off, uint cnt){ struct buf *bp; uint tot=0, m=0, bn=0; // file size limit if ((off > ip->i_size) || (off+cnt < off)){ cu->p_error = E2BIG; return -1; } if (off+cnt > ip->i_size) { cnt = ip->i_size - off; } // read for(tot=0; tot<cnt; tot+=m, off+=m, buf+=m){ m = min(cnt - tot, BLK - off%BLK); bn = bmap(ip, off/BLK, 0); if (bn == 0) { memset(bp->b_data + off%BLK, 0, m); } else { bp = bread(ip->i_dev, bn); memcpy(buf, bp->b_data + off%BLK, m); brelse(bp); } } return cnt; }
// Look for a directory entry in a directory. // If found, set *poff to byte offset of entry. // Caller must have already locked dp. struct inode* dirlookup(struct inode *dp, char *name, uint *poff) { uint off, inum; struct buf *bp; struct dirent *de; if(dp->type != T_DIR) panic("dirlookup not DIR"); for(off = 0; off < dp->logical_size; off += BSIZE){ bp = bread(dp->dev, bmap(dp, off / BSIZE)); for(de = (struct dirent*)bp->data; de < (struct dirent*)(bp->data + BSIZE); de++){ if(de->inum == 0) continue; if(namecmp(name, de->name) == 0){ // entry matches path element if(poff) *poff = off + (uchar*)de - bp->data; inum = de->inum; brelse(bp); return iget(dp->dev, inum); } } brelse(bp); } return 0; }
// PAGEBREAK! // Read data from inode. int readi(struct inode* ip, char* dst, uint off, uint n) { uint tot, m; struct buf* bp; struct superblock sb; // cprintf("readi \n"); sb = sbs[ip->part->number]; if (ip->type == T_DEV) { if (ip->major < 0 || ip->major >= NDEV || !devsw[ip->major].read) return -1; return devsw[ip->major].read(ip, dst, n); } if (off > ip->size || off + n < off) return -1; if (off + n > ip->size) n = ip->size - off; for (tot = 0; tot < n; tot += m, off += m, dst += m) { uint bmapOut = bmap(ip, off / BSIZE); // cprintf("bout %d \n",bmapOut); bp = bread(ip->dev, sb.offset + bmapOut); m = min(n - tot, BSIZE - off % BSIZE); memmove(dst, bp->data + off % BSIZE, m); brelse(bp); } return n; }
void BitmapImage::checkForSolidColor() { m_checkedForSolidColor = true; if (frameCount() > 1) { m_isSolidColor = false; return; } CGImageRef image = frameAtIndex(0); // Currently we only check for solid color in the important special case of a 1x1 image. if (image && CGImageGetWidth(image) == 1 && CGImageGetHeight(image) == 1) { unsigned char pixel[4]; // RGBA static CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB(); RetainPtr<CGContextRef> bmap(AdoptCF, CGBitmapContextCreate(pixel, 1, 1, 8, sizeof(pixel), space, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big)); if (!bmap) return; GraphicsContext(bmap.get()).setCompositeOperation(CompositeCopy); CGRect dst = { {0, 0}, {1, 1} }; CGContextDrawImage(bmap.get(), dst, image); if (pixel[3] == 0) m_solidColor = Color(0, 0, 0, 0); else m_solidColor = Color(pixel[0] * 255 / pixel[3], pixel[1] * 255 / pixel[3], pixel[2] * 255 / pixel[3], pixel[3]); m_isSolidColor = true; } }
/* * get next entry in a directory. */ struct direct * dreaddir(struct dirstuff *dirp) { struct direct *dp; diskaddr_t lbn, d; for (;;) { if (dirp->loc >= (int)dirp->ip->di_size) return (NULL); if (blkoff(&sblock, dirp->loc) == 0) { lbn = lblkno(&sblock, dirp->loc); d = bmap(lbn); if (d == 0) return (NULL); bread(fsbtodb(&sblock, d), dirp->dbuf, (int)dblksize(&sblock, dirp->ip, (int)lbn)); } dp = (struct direct *) (dirp->dbuf + blkoff(&sblock, dirp->loc)); dirp->loc += dp->d_reclen; if (dp->d_ino == 0) continue; return (dp); } }
//PAGEBREAK! // Read data from inode. int readi(struct inode *ip, char *dst, uint off, uint n) { uint tot, m; struct buf *bp; if(ip->type == T_DEV){ if(ip->major < 0 || ip->major >= NDEV || !devsw[ip->major].read) return -1; return devsw[ip->major].read(ip, dst, n); } if(off > ip->size || off + n < off) return -1; if(off + n > ip->size) n = ip->size - off; for(tot=0; tot<n; tot+=m, off+=m, dst+=m){ bp = bread(ip->dev, bmap(ip, off/BSIZE)); m = min(n - tot, BSIZE - off%BSIZE); memmove(dst, bp->data + off%BSIZE, m); brelse(bp); } return n; }
int file_read(struct m_inode * inode, struct file * filp, char * buf, int count) { int left,chars,nr; struct buffer_head * bh; if ((left=count)<=0) return 0; while (left) { if ((nr = bmap(inode,(filp->f_pos)/BLOCK_SIZE))) { if (!(bh=bread(inode->i_dev,nr))) break; } else bh = NULL; nr = filp->f_pos % BLOCK_SIZE; chars = MIN( BLOCK_SIZE-nr , left ); filp->f_pos += chars; left -= chars; if (bh) { char * p = nr + bh->b_data; while (chars-->0) put_fs_byte(*(p++),buf++); brelse(bh); } else { while (chars-->0) put_fs_byte(0,buf++); } } inode->i_atime = CURRENT_TIME; return (count-left)?(count-left):-ERROR; }
// PAGEBREAK! // Write data to inode. int writei(struct inode* ip, char* src, uint off, uint n) { // cprintf("writei \n"); uint tot, m; struct buf* bp; struct superblock sb; sb = sbs[ip->part->number]; if (ip->type == T_DEV) { if (ip->major < 0 || ip->major >= NDEV || !devsw[ip->major].write) return -1; return devsw[ip->major].write(ip, src, n); } if (off > ip->size || off + n < off) return -1; if (off + n > MAXFILE * BSIZE) return -1; for (tot = 0; tot < n; tot += m, off += m, src += m) { uint bmapOut = bmap(ip, off / BSIZE); bp = bread(ip->dev, sb.offset + bmapOut); m = min(n - tot, BSIZE - off % BSIZE); memmove(bp->data + off % BSIZE, src, m); log_write(bp, ip->part->number); brelse(bp); } if (n > 0 && off > ip->size) { ip->size = off; iupdate(ip); } return n; }
/* * write data to a regular file. * */ int writei(struct inode *ip, char *buf, uint off, uint cnt){ struct buf *bp; uint tot=0, m=0, bn=0; if (off+cnt < off){ return -1; } if (off+cnt > MAX_FILESIZ) { cnt = MAX_FILESIZ - off; } // do write. for(tot=0; tot<cnt; tot+=m, off+=m, buf+=m){ m = min(cnt - tot, BLK - off%BLK); bn = bmap(ip, off/BLK, 1); if (bn==0) { panic("bad block."); } else { bp = bread(ip->i_dev, bn); // note here! memcpy(bp->b_data + off%BLK, buf, m); bwrite(bp); brelse(bp); } } // adjust the inode's file size if (cnt > 0 && off > ip->i_size) { ip->i_size = off; iupdate(ip); } return cnt; }
// PAGEBREAK! // Write data to inode. int writei(struct inode *ip, char *src, uint off, uint n) { uint tot, m; struct buf *bp; if(ip->type == T_DEV){ if(ip->major < 0 || ip->major >= NDEV || !devsw[ip->major].write) return -1; return devsw[ip->major].write(ip, src, n); } if(off > ip->size || off + n < off) return -1; if(off + n > MAXFILE*BSIZE) return -1; for(tot=0; tot<n; tot+=m, off+=m, src+=m){ bp = bread(ip->dev, bmap(ip, off/BSIZE)); m = min(n - tot, BSIZE - off%BSIZE); memmove(bp->data + off%BSIZE, src, m); log_write(bp); brelse(bp); } if(n > 0 && off > ip->size){ ip->size = off; iupdate(ip); } return n; }
struct block *bmap_block(struct inode *inode, int blk, int create) { if ((blk = bmap(inode, blk, create)) < 0) return NULL; else if (blk == 0) return MINIX_ZERO_BLOCK; return minix_get_block(inode->i_sb, blk); }
// Check data from inode to see if it is in the buffer cache. int checki(struct inode *ip, int off) { if(off > ip->size) return -1; //cprintf("checki: calling bcheck\n"); return bcheck(ip->dev, bmap(ip, off/BSIZE, 0)); }
static int do_readahead(journal_t *journal, unsigned int start) { int err; unsigned int max, nbufs, next, blocknr; struct buffer_head *bh; struct buffer_head * bufs[MAXBUF]; /* Do up to 128K of readahead */ max = start + (128 * 1024 / journal->j_blocksize); if (max > journal->j_maxlen) max = journal->j_maxlen; /* Do the readahead itself. We'll submit MAXBUF buffer_heads at * a time to the block device IO layer. */ nbufs = 0; for (next = start; next < max; next++) { blocknr = next; if (journal->j_inode) blocknr = bmap(journal->j_inode, next); if (!blocknr) { printk (KERN_ERR "JFS: bad block at offset %u\n", next); err = -EIO; goto failed; } bh = getblk(journal->j_dev, blocknr, journal->j_blocksize); if (!bh) { err = -ENOMEM; goto failed; } if (!buffer_uptodate(bh) && !buffer_locked(bh)) { bufs[nbufs++] = bh; if (nbufs == MAXBUF) { ll_rw_block(READ, nbufs, bufs); brelse_array(bufs, nbufs); nbufs = 0; } } else brelse(bh); } if (nbufs) ll_rw_block(READ, nbufs, bufs); err = 0; failed: if (nbufs) brelse_array(bufs, nbufs); return err; }
//return age of buffer containing data, or 0 if no buffer int agei(struct inode *ip, uint off) { if (ip->type == T_DEV) return 0; if(off > ip->size) return 0; return bage(ip->dev, bmap(ip, off/BSIZE, 0)); }
// Write data to inode. int writei(struct inode *ip, char *src, uint off, uint n) { uint tot, m; struct buf *bp; char *addr; if(ip->type == T_DEV){ if(ip->major < 0 || ip->major >= NDEV || !devsw[ip->major].write) return -1; return devsw[ip->major].write(ip, src, n); } if(off > ip->size || off + n < off) return -1; if(ip->type == T_SMALLFILE){ // handle T_SMALLFILE // cprintf("before n in readi : %d\t off = %d\t size = %d\n", n, off, ip->size); if(off + n > 52) n = 52 - off; addr = (char*)(ip->addrs); // get NDIRECT address memmove(addr + off, src, n); off += n; ip->size = off; iupdate(ip); return n; // cprintf("after n in readi : %d\t off = %d\t size = %d\n", n, off, ip->size); // cprintf("write addr: %s\n", *(addr + off)); } else { // handle T_FILE if(off + n > MAXFILE*BSIZE) n = MAXFILE*BSIZE - off; for(tot=0; tot<n; tot+=m, off+=m, src+=m){ uint sector_number = bmap(ip, off/BSIZE); if(sector_number == 0){ //failed to find block n = tot; //return number of bytes written so far break; } bp = bread(ip->dev, sector_number); m = min(n - tot, BSIZE - off%BSIZE); memmove(bp->data + off%BSIZE, src, m); bwrite(bp); brelse(bp); } } if(n > 0 && off > ip->size){ ip->size = off; iupdate(ip); // cprintf("last n in readi : %d\t off = %d\t size = %d\n", n, off, ip->size); } return n; }
void getblk(Ram *r, long bno, char *buf) { long dbno; if ((dbno = bmap(r, bno)) == 0) { memset(buf, 0, BLSIZE); return; } seek(tapefile, dbno*BLSIZE, 0); if (read(tapefile, buf, BLSIZE) != BLSIZE) error("bad read"); }
void pass3(struct dinode *ip) { struct direct dbuf[NDIR]; long doff; struct direct *dp; register i, j; int k; daddr_t d; ino_t kno; if((ip->di_mode&IFMT) != IFDIR) return; l4tol(iaddr, ip->di_addr, NADDR); doff = 0; for(i=0;; i++) { if(doff >= ip->di_size) break; d = bmap(i); if(d == 0) break; bread(d, (char *)dbuf, sizeof(dbuf)); for(j=0; j<NDIR; j++) { if(doff >= ip->di_size) break; doff += sizeof(struct direct); dp = dbuf+j; kno = dp->d_ino; if(kno == 0) continue; if(aflg==0 && dotname(dp)) continue; if(ilist[0] == 0) goto pr; for(k=0; ilist[k] != 0; k++) if(ilist[k] == kno) goto pr; continue; pr: printf("%u ", kno); pname(ino, 0); printf("/%.14s", dp->d_name); if (lookup(kno, 0)) printf("/."); printf("\n"); } } }
static int rw_swap_page_base(int rw, swp_entry_t entry, struct page *page) { unsigned long offset; int zones[PAGE_SIZE/512]; int zones_used; kdev_t dev = 0; int block_size; struct inode *swapf = 0; if (rw == READ) { ClearPageUptodate(page); kstat.pswpin++; } else kstat.pswpout++; get_swaphandle_info(entry, &offset, &dev, &swapf); if (dev) { zones[0] = offset; zones_used = 1; block_size = PAGE_SIZE; } else if (swapf) { int i, j; unsigned int block = offset << (PAGE_SHIFT - swapf->i_sb->s_blocksize_bits); block_size = swapf->i_sb->s_blocksize; for (i=0, j=0; j< PAGE_SIZE ; i++, j += block_size) if (!(zones[i] = bmap(swapf,block++))) { printk("rw_swap_page: bad swap file\n"); return 0; } zones_used = i; dev = swapf->i_dev; } else { return 0; } /* block_size == PAGE_SIZE/zones_used */ brw_page(rw, page, dev, zones, block_size); /* Note! For consistency we do all of the logic, * decrementing the page count, and unlocking the page in the * swap lock map - in the IO completion handler. */ return 1; }
//// 文件读函数 - 根据i节点和文件结构,读取文件中数据。 // 由i节点我们可以知道设备号,由filp结构可以知道文件中当前读写指针位置。buf指定 // 用户空间中缓冲区位置,count是需要读取字节数。返回值是实际读取的字节数,或出错号(小于0). int file_read(struct m_inode * inode, struct file * filp, char * buf, int count) { int left,chars,nr; struct buffer_head * bh; // 首先判断参数的有效性。若需要读取的字节数count小于等于0,则返回0.若还需要读 // 取的字节数不等于0,就循环执行下面操作,直到数据全部读出或遇到问题。在读循环 // 操作过程中,我们根据i节点和文件表结构信息,并利用bmap()得到包含文件当前读写 // 位置的数据块在设备上对应的逻辑块号nr。若nr不为0,则从i节点指定的设备上读取该 // 逻辑块。如果读操作是吧则退出循环。若nr为0,表示指定的数据块不存在,置缓冲块 // 指针为NULL。(filp->f_pos)/BLOCK_SIZE用于计算出文件当前指针所在的数据块号。 if ((left=count)<=0) return 0; while (left) { if ((nr = bmap(inode,(filp->f_pos)/BLOCK_SIZE))) { if (!(bh=bread(inode->i_dev,nr))) break; } else bh = NULL; // 接着我们计算文件读写指针在数据块中的偏移值nr,则在该数据块中我们希望读取的 // 字节数为(BLOCK_SIZE-nr)。然后和现在还需读取的字节数left做比较。其中小值 // 即为本次操作需读取的字节数chars。如果(BLOCK_SIZE-nr) > left,则说明该块 // 是需要读取的最后一块数据。反之还需要读取下一块数据。之后调整读写文件指针。 // 指针前移此次将读取的字节数chars,剩余字节计数left相应减去chars。 nr = filp->f_pos % BLOCK_SIZE; chars = MIN( BLOCK_SIZE-nr , left ); filp->f_pos += chars; left -= chars; // 若上面从设备上读到了数据,则将p指向缓冲块中开始读取数据的位置,并且复制chars // 字节到用户缓冲区buf中。否则往用户缓冲区中填入chars个0值字节。 if (bh) { char * p = nr + bh->b_data; while (chars-->0) put_fs_byte(*(p++),buf++); brelse(bh); } else { while (chars-->0) put_fs_byte(0,buf++); } } // 修改该i节点的访问时间为当前时间。返回读取的字节数,若读取字节数为0,则返回 // 出错号。CURRENT_TIME是定义在include/linux/sched.h中的宏,用于计算UNIX时间。 // 即从1970年1月1日0时0分0秒开始,到当前的时间,单位是秒。 inode->i_atime = CURRENT_TIME; return (count-left)?(count-left):-ERROR; }
void pass1(struct dinode *ip) { struct direct dbuf[NDIR]; long doff; struct direct *dp; register i, j; int k; daddr_t d; ino_t kno; if((ip->di_mode&IFMT) != IFDIR) return; l4tol(iaddr, ip->di_addr, NADDR); doff = 0; for(i=0;; i++) { if(doff >= ip->di_size) break; d = bmap(i); if(d == 0) break; bread(d, (char *)dbuf, BSIZE); for(j=0; j<NDIR; j++) { if(doff >= ip->di_size) break; doff += sizeof(struct direct); dp = &dbuf[j]; kno = dp->d_ino; if(kno == 0) continue; if(kno >= nfiles || kno < 0) { printf("%5u bad; %u/%.14s\n", kno, ino, dp->d_name); nerror++; continue; } for (k=0; ilist[k] != 0; k++) if (ilist[k]==kno) { printf("%5u arg; %u/%.14s\n", kno, ino, dp->d_name); nerror++; } ecount[kno]++; if (ecount[kno] == 0) ecount[kno] = (char) 0377; } } }
/* * Used in mpage_readpages() fs/mpage.c * Keeps a connection between block and its page */ void dedup_update_block_page(struct page *page) { struct address_space *mapping = page->mapping; struct inode *inode = (mapping) ? page->mapping->host : NULL; if (inode != NULL) { // get the block number sector_t page_block = bmap(inode, page->index); // Check if the block is inside dedup range if (dedup_is_in_range(page_block)) { // Update block's page reference blocksArray.pages[page_block - start_block] = page; } } else printk("inode is NULL :(\n"); }
main(int argc, char *argv[]) { int fd; if (argc > 1) device = argv[1]; fd = open(device, O_RDONLY); if (fd < 0){ printf("open %s failed\n", device); exit(1); } super(fd); gd(fd); bmap(fd); imap(fd); inode(fd); dir(fd); }
static int jread(struct buffer_head **bhp, journal_t *journal, unsigned int offset) { unsigned int blocknr; struct buffer_head *bh; *bhp = NULL; J_ASSERT (offset < journal->j_maxlen); blocknr = offset; if (journal->j_inode) blocknr = bmap(journal->j_inode, offset); if (!blocknr) { printk (KERN_ERR "JFS: bad block at offset %u\n", offset); return -EIO; } bh = getblk(journal->j_dev, blocknr, journal->j_blocksize); if (!bh) return -ENOMEM; if (!buffer_uptodate(bh)) { /* If this is a brand new buffer, start readahead. Otherwise, we assume we are already reading it. */ if (!buffer_req(bh)) do_readahead(journal, offset); wait_on_buffer(bh); } if (!buffer_uptodate(bh)) { printk (KERN_ERR "JFS: Failed to read block at offset %u\n", offset); brelse(bh); return -EIO; } *bhp = bh; return 0; }
sector_t wrapfs_bmap(struct address_space *mapping, sector_t block) { int err = -EINVAL; struct inode *inode, *lower_inode; sector_t (*bmap)(struct address_space *, sector_t); wrapfs_debug(""); inode = (struct inode *)mapping->host; wrapfs_debug_aops(WRAPFS_SB(inode->i_sb)->wrapfs_debug_a_ops, ""); lower_inode = wrapfs_lower_inode(inode); if (!lower_inode) goto out; bmap = lower_inode->i_mapping->a_ops->bmap; if (bmap) err = bmap(lower_inode->i_mapping, block); out: wrapfs_debug_aops(WRAPFS_SB(inode->i_sb)->wrapfs_debug_a_ops, "err : %d", err); return err; }
void getblk(Ram *r, long bno, char *buf) { long dbno; if ((dbno = bmap(r, bno)) == 0) { memset(buf, 0, BLSIZE); return; } if ((vlong)(dbno+1)*BLSIZE > tapelen) { fprint(2, "read past end of tape: %lld\n", (vlong)dbno*BLSIZE); memset(buf, 0, BLSIZE); return; } seek(tapefile, dbno*BLSIZE, 0); if (readn(tapefile, buf, BLSIZE) != BLSIZE){ fprint(2, "readn at %lld: %r\n", (vlong)dbno*BLSIZE); error("bad read"); } }
void pass2(struct dinode *ip) { struct direct dbuf[NDIR]; long doff; struct direct *dp; register i, j; int k; struct htab *hp; daddr_t d; ino_t kno; if((ip->di_mode&IFMT) != IFDIR) return; l4tol(iaddr, ip->di_addr, NADDR); doff = 0; for(i=0;; i++) { if(doff >= ip->di_size) break; d = bmap(i); if(d == 0) break; bread(d, (char *)dbuf, sizeof(dbuf)); for(j=0; j<NDIR; j++) { if(doff >= ip->di_size) break; doff += sizeof(struct direct); dp = dbuf+j; kno = dp->d_ino; if(kno == 0) continue; hp = lookup(kno, 0); if(hp == 0) continue; if(dotname(dp)) continue; hp->h_pino = ino; for(k=0; k<DIRSIZ; k++) hp->h_name[k] = dp->d_name[k]; } } }
/* read data from inode */ int iread(struct inode *ip, char *dest, uint32_t off, uint32_t n) { uint32_t tot, m; struct buf *bp; /* is a char device? */ if (S_ISCHR(ip->mode)) { return dtable[ip->zone[0]].read(ip, dest, n); } /* 偏移过大 || 溢出*/ if (off > ip->size || off + n < off) { panic("iread: incorrect offet"); return -1; } if (off + n > ip->size) { n = ip->size - off; } /* tot: 已读取的字节数 * n: 要读取的字节数 * off: 当前文件指针偏移 * m: 当次循环要读取的字节数 */ for (tot = 0; tot < n; tot += m, off += m, dest += m) { bp = bread(ip->dev, bmap(ip, off/BSIZE)); /* 每个循环读取的数据可分两种情况: * - 从当前文件偏移读到该扇区结束 * - 从当前文件偏移读到 *满足要读取的字节数* * 每次选择较小的那个 */ m = min(n - tot, BSIZE - off%BSIZE); /* 从当前偏移相对于该扇区的偏移处起开始读取 * (在中间的循环这个值常常是0) */ memcpy(dest, bp->data + off%BSIZE, m); brelse(bp); } return n; }
void rw_swap_page(int rw, unsigned int nr, char * buf) { unsigned int zones[4]; int i; if (swap_device) { ll_rw_page(rw,swap_device,nr,buf); return; } if (swap_file) { nr <<= 2; for (i = 0; i < 4; i++) if (!(zones[i] = bmap(swap_file,nr++))) { printk("rw_swap_page: bad swap file\n"); return; } ll_rw_swap_file(rw,swap_file->i_dev, zones,4,buf); return; } printk("ll_swap_page: no swap file or device\n"); }
/* * Conversion of logical to physical block numbers for the journal * * On external journals the journal blocks are identity-mapped, so * this is a no-op. If needed, we can use j_blk_offset - everything is * ready. */ int journal_bmap(journal_t *journal, unsigned long blocknr, unsigned long *retp) { int err = 0; unsigned long ret; if (journal->j_inode) { ret = (unsigned long)bmap(journal->j_inode, (sector_t)blocknr); if (ret) *retp = ret; else { printk(KERN_ALERT "%s: journal block not found " "at offset %lu ...\n", __FUNCTION__, blocknr); err = -EIO; __journal_abort_soft(journal, err); } } else { *retp = blocknr; /* +journal->j_blk_offset */ } return err; }
inoptr srch_dir(inoptr wd, char *compname) { int curentry; blkno_t curblock; struct direct *buf; int nblocks; uint16_t inum; nblocks = (wd->c_node.i_size + BLKMASK) >> BLKSHIFT; for(curblock=0; curblock < nblocks; ++curblock) { buf = (struct direct *)bread(wd->c_dev, bmap(wd, curblock, 1), 0); for(curentry = 0; curentry < (512/DIR_LEN); ++curentry) { if(namecomp(compname, buf[curentry].d_name)) { inum = buf[curentry & 0x1f].d_ino; brelse(buf); return i_open(wd->c_dev, inum); } } brelse(buf); } return NULLINODE; }