func (c *server_InodeTbl) writeInode(xp *common.Inode) { // Calculate the block number we need inum := xp.Inum - 1 info := xp.Devinfo inodes_per_block := info.Blocksize / common.V2_INODE_SIZE ioffset := inum % inodes_per_block block_num := info.MapOffset + (inum / inodes_per_block) // Load the inode from the disk bp := c.bcache.GetBlock(info.Devnum, block_num, common.INODE_BLOCK, common.NORMAL) inodeb := bp.Block.(common.InodeBlock) // TODO: Update times, handle read-only filesystems bp.Dirty = true // Copy the disk_inode from rip into the inode block inodeb[ioffset] = *xp.Disk_Inode xp.Dirty = false c.bcache.PutBlock(bp, common.INODE_BLOCK) }
func (c *server_InodeTbl) loadInode(xp *common.Inode) { // The count at this point is guaranteed to be > 0, so the device cannot // be unmounted until the load has completed and the inode has been 'put' inum := xp.Inum - 1 info := xp.Devinfo inodes_per_block := info.Blocksize / common.V2_INODE_SIZE ioffset := inum % inodes_per_block blocknum := info.MapOffset + (inum / inodes_per_block) // Load the inode from the disk and create an in-memory version of it bp := c.bcache.GetBlock(info.Devnum, blocknum, common.INODE_BLOCK, common.NORMAL) inodeb := bp.Block.(common.InodeBlock) // We have the full block, now get the correct inode entry inode_d := &inodeb[ioffset] xp.Disk_Inode = inode_d xp.Dirty = false xp.Mounted = nil }
func search_dir(dirp *common.Inode, path string, inum *int, op dirop) error { // TODO: Check permissions (see minix source) devinfo := dirp.Devinfo blocksize := devinfo.Blocksize // step through the directory on block at a time var bp *common.CacheBlock var dp *common.Disk_dirent old_slots := int(dirp.Size / common.DIR_ENTRY_SIZE) new_slots := 0 e_hit := false match := false extended := false for pos := 0; pos < int(dirp.Size); pos += blocksize { b := common.ReadMap(dirp, pos, dirp.Bcache) // get block number if dirp.Bcache == nil { panic(fmt.Sprintf("No block cache: %q", dirp)) } bp = dirp.Bcache.GetBlock(devinfo.Devnum, b, common.DIRECTORY_BLOCK, common.NORMAL) if bp == nil { panic("get_block returned NO_BLOCK") } // Search the directory block dirarr := bp.Block.(common.DirectoryBlock) for i := 0; i < len(dirarr); i++ { dp = &dirarr[i] new_slots++ if new_slots > old_slots { // not found, but room left if op == ENTER { e_hit = true } break } // Match occurs if string found if op != ENTER && dp.Inum != 0 { if op == IS_EMPTY { // If this succeeds, dir is not empty if !dp.HasName(".") && !dp.HasName("..") { log.Printf("Found entry: %s (%d)", dp.String(), dp.Inum) match = true } } else { if dp.HasName(path) { match = true } } } if match { var r error = nil // LOOK_UP or DELETE found what it wanted if op == IS_EMPTY { r = common.ENOTEMPTY } else if op == DELETE { // TODO: Save inode for recovery dp.Inum = 0 // erase entry bp.Dirty = true dirp.Dirty = true } else { *inum = int(dp.Inum) } dirp.Bcache.PutBlock(bp, common.DIRECTORY_BLOCK) return r } // Check for free slot for the benefit of ENTER if op == ENTER && dp.Inum == 0 { e_hit = true // we found a free slot break } } // The whole block has been searched or ENTER has a free slot if e_hit { // e_hit set if ENTER can be performed now break } dirp.Bcache.PutBlock(bp, common.DIRECTORY_BLOCK) // otherwise continue searching dir } // The whole directory has now been searched if op != ENTER { if op == IS_EMPTY { return nil } else { return common.ENOENT } } // This call is for ENTER. If no free slot has been found so far, try to // extend directory. if !e_hit { // directory is full and no room left in last block new_slots++ // increase directory size by 1 entry // TODO: Does this rely on overflow? Does it work? if new_slots == 0 { // dir size limited by slot count (overflow?) return common.EFBIG } var err error bp, err = common.NewBlock(dirp, int(dirp.Size), common.DIRECTORY_BLOCK, dirp.Bcache) if err != nil { return err } dirarr := bp.Block.(common.DirectoryBlock) dp = &dirarr[0] extended = true } // 'bp' now points to a directory block with space. 'dp' points to a slot // in that block. // Set the name of this directory entry pathb := []byte(path) if len(pathb) < common.NAME_MAX { dp.Name[len(pathb)] = 0 } for i := 0; i < common.NAME_MAX && i < len(pathb); i++ { dp.Name[i] = pathb[i] } dp.Inum = uint32(*inum) bp.Dirty = true dirp.Bcache.PutBlock(bp, common.DIRECTORY_BLOCK) // TODO: update times dirp.Dirty = true if new_slots > old_slots { dirp.Size = (int32(new_slots * common.DIR_ENTRY_SIZE)) // Send the change to disk if the directory is extended if extended { // TODO: Write this inode out to the block cache dirp.Icache.FlushInode(dirp) } } return nil }