def create_block_bitmap(group_number): def fillbitmap(first_data_bn, blocks_per_group): remaining_blocks_count = first_data_bn % 8 for b in range(first_data_bn // 8): yield 255 if remaining_blocks_count != 0: yield 255 >> (8 - remaining_blocks_count) free_blocks = (blocks_per_group - first_data_bn) // 8 for b in range(free_blocks): yield 0 gbn = fs.gpn_to_bn( group_number, fs.bytes_to_int(superblock.get_field(superblock.s_blocks_per_group))) bitmap_bytes_count = math.ceil( fs.bytes_to_int(superblock.get_field(superblock.s_blocks_per_group)) / 8) gdtable_block = gdtable.get_gdtableblock(group_number) bitmap_bn = fs.bytes_to_int( gdtable_block.get_field(group_number, gdtable_block.bg_block_bitmap)) blockbitmap.block_bitmap.load(bitmap_bn) blockbitmap.block_bitmap.block_buffer[:bitmap_bytes_count] = bytes( fillbitmap( fs.bytes_to_int(superblock.get_field( superblock.s_first_data_block)) + 1 if group_number == 0 else fs.bytes_to_int( superblock.get_field(superblock.s_first_data_block)), fs.bytes_to_int(superblock.get_field( superblock.s_blocks_per_group)))) blockbitmap.block_bitmap.unload(bitmap_bn)
def create_inode_table(): first_data_block = fs.bytes_to_int( superblock.get_field(superblock.s_first_data_block)) inodetable_block = inodetable.load_inode(0) table_number = inodetable.get_table_number(0) inodetable_block.set_field( table_number, inodetable_block.i_mode, inodetable.S_IFDIR | inodetable.S_IXUSR | inodetable.S_IRUSR | inodetable.S_IWUSR | inodetable.S_IXOTH | inodetable.S_IROTH | inodetable.S_IWOTH | inodetable.S_IWGRP | inodetable.S_IRGRP | inodetable.S_IXGRP) inodetable_block.set_field(table_number, inodetable_block.i_uid, 0) inodetable_block.set_field(table_number, inodetable_block.i_size, 0) inodetable_block.set_field(table_number, inodetable_block.i_atime, 0) inodetable_block.set_field(table_number, inodetable_block.i_mtime, 0) inodetable_block.set_field(table_number, inodetable_block.i_ctime, int(time.time())) inodetable_block.set_field(table_number, inodetable_block.i_dtime, 0) inodetable_block.set_field(table_number, inodetable_block.i_gid, 0) inodetable_block.set_field(table_number, inodetable_block.i_blocks, 1) inodetable_block.set_field(table_number, inodetable_block.i_flags, 0) block = bytearray(inodetable_block.i_block[sysblock.SIZE_INDEX]) block[:superblock.s_first_data_block[sysblock.SIZE_INDEX]] = \ first_data_block.to_bytes(superblock.s_first_data_block[sysblock.SIZE_INDEX], 'little') inodetable_block.set_field(table_number, inodetable_block.i_block, bytes(block)) inodetable_block.set_field( table_number, inodetable_block.i_pad, bytes(inodetable_block.i_pad[sysblock.SIZE_INDEX])) inodetable.unload_inode(0)
def _check_index(self, index): if self.offset_bn + (index * self.struct_size // (fs.bytes_to_int(superblock.get_field(superblock.s_log_block_size)) * 1024)) \ != self.block_buffer_bn: raise IndexError( "Can't read structure #{0} in this block. Offset: {1}. Block number: {2}" .format(index, self.offset_bn, self.block_buffer_bn))
def create_gdtable(group_number): gdtable.load_gdtable(group_number) block_size = fs.bytes_to_int( superblock.get_field(superblock.s_log_block_size)) * 1024 blocks_per_group = fs.bytes_to_int( superblock.get_field(superblock.s_blocks_per_group)) inodes_per_group = fs.bytes_to_int( superblock.get_field(superblock.s_inodes_per_group)) groups_count = fs.get_groups_count( fs.bytes_to_int(superblock.get_field(superblock.s_blocks_count)), fs.bytes_to_int(superblock.get_field(superblock.s_blocks_per_group))) gdtable_blocks_count = math.ceil(groups_count * fs.GD_SIZE / block_size) itable_blocks_count = math.ceil(inodes_per_group * fs.INODE_SIZE / block_size) for g in range(groups_count): gdtable_block = gdtable.get_gdtableblock(g) gdtable_block.set_field( g, gdtable_block.bg_block_bitmap, g * blocks_per_group + gdtable_blocks_count + 1) gdtable_block.set_field( g, gdtable_block.bg_inode_bitmap, g * blocks_per_group + gdtable_blocks_count + 2) gdtable_block.set_field( g, gdtable_block.bg_inode_table, g * blocks_per_group + gdtable_blocks_count + 3) if g == 0: gdtable_block.set_field( g, gdtable_block.bg_free_blocks_count, blocks_per_group - gdtable_blocks_count - itable_blocks_count - 4) gdtable_block.set_field(g, gdtable_block.bg_free_inodes_count, inodes_per_group - 1) gdtable_block.set_field(g, gdtable_block.bg_used_dirs_count, 1) else: gdtable_block.set_field( g, gdtable_block.bg_free_blocks_count, blocks_per_group - gdtable_blocks_count - itable_blocks_count - 3) gdtable_block.set_field(g, gdtable_block.bg_free_inodes_count, inodes_per_group) gdtable_block.set_field(g, gdtable_block.bg_used_dirs_count, 0) gdtable_block.set_field( g, gdtable_block.bg_pad, bytes(gdtable_block.bg_pad[sysblock.SIZE_INDEX])) gdtable.unload_gdtable(group_number)
def unload_gdtable(group_number): group_bn = fs.gpn_to_bn( group_number, fs.bytes_to_int(superblock.get_field(superblock.s_blocks_per_group)) ) for bn, gdtable_block in enumerate(gdtable_blocks): gdtable_block.unload(bn + group_bn + 1)
def set_field(self, index, field, value): self._check_index(index) index %= fs.bytes_to_int( superblock.get_field( superblock.s_log_block_size)) * 1024 // self.struct_size self.block_buffer[index * self.struct_size + field[OFFSET_INDEX]: index * self.struct_size + field[OFFSET_INDEX] + field[SIZE_INDEX]] = \ sysblock.to_bytes(value, field[SIZE_INDEX])
def get_field(self, index, field): self._check_index(index) index %= fs.bytes_to_int( superblock.get_field( superblock.s_log_block_size)) * 1024 // self.struct_size return self.block_buffer[index * self.struct_size + field[OFFSET_INDEX]:index * self.struct_size + field[OFFSET_INDEX] + field[SIZE_INDEX]]
def unload_inode(number): block_size = fs.bytes_to_int(superblock.get_field(superblock.s_log_block_size)) * 1024 for i, block in enumerate(inodetable_blocks_list): if block.first_inode_number <= number < block.first_inode_number + block_size // fs.INODE_SIZE: block.unload(block.block_buffer_bn) if block.loads_count <= 1: del inodetable_blocks_list[i] else: block.loads_count -= 1 break
def extend_file_blocks(inode_block, inode, i_block): inode_tn = get_table_number(inode) gpn = get_group_number(inode) bg_block = gdtable.get_gdtableblock(gpn) blockbitmap.block_bitmap.load(fs.bytes_to_int(bg_block.get_field(gpn, bg_block.bg_block_bitmap))) igbn = blockbitmap.find_first_free_block() blocks_count = fs.bytes_to_int(inode_block.get_field( inode_tn, inode_block.i_blocks )) i_block[blocks_count * fs.ADDRESS_SIZE: (blocks_count+1) * fs.ADDRESS_SIZE] = fs.int_to_bytes( igbn + gpn * fs.bytes_to_int(superblock.get_field(superblock.s_blocks_per_group)), fs.ADDRESS_SIZE ) inode_block.set_field(inode_tn, inode_block.i_block, i_block) inode_block.set_field(inode_tn, inode_block.i_blocks, blocks_count + 1) blockbitmap.set_used_block(igbn) blockbitmap.block_bitmap.unload(fs.bytes_to_int(bg_block.get_field(gpn, bg_block.bg_block_bitmap))) return igbn + gpn * fs.bytes_to_int(superblock.get_field(superblock.s_blocks_per_group))
def load_inode(number): block_size = fs.bytes_to_int(superblock.get_field(superblock.s_log_block_size)) * 1024 for block in inodetable_blocks_list: if block.first_inode_number <= number <= block.first_inode_number + block_size // fs.INODE_SIZE: block.loads_count += 1 return block gn = number // fs.bytes_to_int(superblock.get_field(superblock.s_inodes_per_group)) table_number = get_table_number(number) gdtable_block = gdtable.get_gdtableblock(gn) inode_table_bn = fs.bytes_to_int(gdtable_block.get_field(gn, gdtable_block.bg_inode_table)) inode_bn = inode_table_bn + table_number * fs.INODE_SIZE // block_size inode_table_block = systableblock.SysTableBlock(fs.INODE_TYPE, inode_table_bn) inode_table_block.init_struct(fs.INODE_NAME) inode_table_block.load(inode_bn) inode_table_block.first_inode_number = (inode_bn - inode_table_bn) * block_size // fs.INODE_SIZE \ + gn * fs.bytes_to_int(superblock.get_field(superblock.s_inodes_per_group)) inode_table_block.loads_count = 1 inodetable_blocks_list.append(inode_table_block) return inode_table_block
def create_inode_bitmap(group_number): bitmap_bytes_count = math.ceil( fs.bytes_to_int(superblock.get_field(superblock.s_inodes_per_group)) / 8) gdtable_block = gdtable.get_gdtableblock(group_number) bitmap_bn = fs.bytes_to_int( gdtable_block.get_field(group_number, gdtable_block.bg_inode_bitmap)) inodebitmap.inode_bitmap.load(bitmap_bn) inodebitmap.inode_bitmap.block_buffer[:bitmap_bytes_count] = bytes( bitmap_bytes_count) if group_number == 0: inodebitmap.inode_bitmap.block_buffer[:1] = b'\x01' inodebitmap.inode_bitmap.unload(bitmap_bn)
def write_by_offset(fd, buf, nbytes): inode = fdtable.get_inode(fd) offset = fdtable.get_offset(fd) inode_tn = inodetable.get_table_number(inode) file_inodetable_block = inodetable.load_inode(inode) i_block = file_inodetable_block.get_field(inode_tn, file_inodetable_block.i_block) file_size = fs.bytes_to_int( file_inodetable_block.get_field(inode_tn, file_inodetable_block.i_size)) blocks_count = fs.bytes_to_int( file_inodetable_block.get_field(inode_tn, file_inodetable_block.i_blocks)) block_size = fs.bytes_to_int( superblock.get_field(superblock.s_log_block_size)) * 1024 lbn = offset // block_size b_offset = offset % block_size if offset + nbytes > file_size: if b_offset + nbytes > block_size or lbn == blocks_count: inodetable.extend_file_blocks(file_inodetable_block, inode, i_block) file_inodetable_block.set_field(inode_tn, file_inodetable_block.i_size, offset + nbytes) bn = inodetable.lbn_to_bn(lbn, i_block) data_block_buffer.load(bn) if b_offset + nbytes > block_size: first_bytes_count = block_size - b_offset if first_bytes_count != 0: data_block_buffer.set_bytes(b_offset, buf[:first_bytes_count]) data_block_buffer.unload(bn) bn = inodetable.lbn_to_bn(lbn + 1, i_block) data_block_buffer.load(bn) data_block_buffer.set_bytes(0, buf[first_bytes_count:nbytes]) else: data_block_buffer.set_bytes(b_offset, buf) data_block_buffer.unload(bn) fdtable.set_offset(fd, offset + nbytes) file_inodetable_block.set_field(inode_tn, file_inodetable_block.i_mtime, int(time.time())) inodetable.unload_inode(inode)
def free_file_blocks(inode_block, inode, i_block): blocks_per_group = fs.bytes_to_int(superblock.get_field(superblock.s_blocks_per_group)) inode_tn = get_table_number(inode) gpn = get_group_number(inode) blocks_count = fs.bytes_to_int(inode_block.get_field( inode_tn, inode_block.i_blocks )) if blocks_count > 0: bg_block = gdtable.get_gdtableblock(gpn) blockbitmap.block_bitmap.load(fs.bytes_to_int(bg_block.get_field(gpn, bg_block.bg_block_bitmap))) first_blocks = [fs.bytes_to_int(i_block[i: i + fs.ADDRESS_SIZE]) for i in range(0, blocks_count * fs.ADDRESS_SIZE, fs.ADDRESS_SIZE)] for bn in first_blocks: blockbitmap.set_free_block(fs.bn_to_igbn(bn, blocks_per_group)) blockbitmap.block_bitmap.unload(fs.bytes_to_int(bg_block.get_field(gpn, bg_block.bg_block_bitmap)))
def write_to_end(fd, buf, nbytes): inode = fdtable.get_inode(fd) inode_tn = inodetable.get_table_number(inode) file_inodetable_block = inodetable.load_inode(inode) i_block = file_inodetable_block.get_field(inode_tn, file_inodetable_block.i_block) file_size = fs.bytes_to_int( file_inodetable_block.get_field(inode_tn, file_inodetable_block.i_size)) block_size = fs.bytes_to_int( superblock.get_field(superblock.s_log_block_size)) * 1024 last_block_size = file_size % block_size if last_block_size == 0: last_bn = inodetable.extend_file_blocks(file_inodetable_block, inode, i_block) else: last_bn = inodetable.get_last_file_bn(i_block) data_block_buffer.load(last_bn) if last_block_size + nbytes > block_size: last_bn = inodetable.extend_file_blocks(file_inodetable_block, inode, i_block) remaining_bytes_count = block_size - last_block_size data_block_buffer.set_bytes(last_block_size, buf[:remaining_bytes_count]) data_block_buffer.unload(data_block_buffer.block_number) data_block_buffer.load(last_bn) data_block_buffer.set_bytes(0, buf[remaining_bytes_count:nbytes]) else: data_block_buffer.set_bytes(last_block_size, buf[:nbytes]) file_inodetable_block.set_field(inode_tn, file_inodetable_block.i_size, file_size + nbytes) data_block_buffer.unload(last_bn) file_inodetable_block.set_field(inode_tn, file_inodetable_block.i_mtime, int(time.time())) inodetable.unload_inode(inode)
def read_by_offset(fd, nbytes): inode = fdtable.get_inode(fd) offset = fdtable.get_offset(fd) inode_tn = inodetable.get_table_number(inode) file_inodetable_block = inodetable.load_inode(inode) i_block = file_inodetable_block.get_field(inode_tn, file_inodetable_block.i_block) file_size = fs.bytes_to_int( file_inodetable_block.get_field(inode_tn, file_inodetable_block.i_size)) block_size = fs.bytes_to_int( superblock.get_field(superblock.s_log_block_size)) * 1024 if offset >= file_size: raise OffsetError(offset) lbn = offset // block_size b_offset = offset % block_size buf = bytearray() if b_offset + nbytes > block_size: first_bytes_count = block_size - b_offset data_block_buffer.load(inodetable.lbn_to_bn(lbn, i_block)) buf[:first_bytes_count] = data_block_buffer.get_bytes( b_offset, first_bytes_count) data_block_buffer.load(inodetable.lbn_to_bn(lbn + 1, i_block)) buf[first_bytes_count:nbytes] = data_block_buffer.get_bytes( 0, nbytes - first_bytes_count) else: data_block_buffer.load(inodetable.lbn_to_bn(lbn, i_block)) buf[:] = data_block_buffer.get_bytes(b_offset, nbytes) fdtable.set_offset(fd, offset + nbytes) file_inodetable_block.set_field(inode_tn, file_inodetable_block.i_atime, int(time.time())) inodetable.unload_inode(inode) return bytes(buf)
def create_file_record(path, mode): if path == '/': raise FileAlreadyExistsError('/') names = [n for n in path.split('/') if n != ''] bg_block = gdtable.get_gdtableblock(0) inodebitmap.inode_bitmap.load( fs.bytes_to_int(bg_block.get_field(0, bg_block.bg_inode_bitmap))) inode_ign = inodebitmap.find_first_free_inode() inode_n = fs.ign_to_in( 0, fs.bytes_to_int(superblock.get_field(superblock.s_inodes_per_group)), inode_ign) dir_table_in = 0 dir_inodetable_block = inodetable.load_inode(dir_table_in) dir_in = 0 perm = inodetable.S_IRUSR | inodetable.S_IRGRP | inodetable.S_IROTH if not permissions.check_file_permissions(dir_inodetable_block, dir_in, perm): raise permissions.PermissionsError(perm) if len(names) > 1: for n in names[:-1]: offset = filerecord.find_file_record(dir_inodetable_block, dir_table_in, n) inodetable.unload_inode(dir_in) if offset is None: raise DirNotFoundError(n) dir_in = filerecord.get_record_inode_number(offset) dir_table_in = inodetable.get_table_number(dir_in) dir_inodetable_block = inodetable.load_inode(dir_in) if not permissions.check_file_permissions(dir_inodetable_block, dir_in, perm): raise permissions.PermissionsError(perm) if fs.bytes_to_int( dir_inodetable_block.get_field(dir_table_in, dir_inodetable_block.i_mode) ) & inodetable.S_IFDIR != inodetable.S_IFDIR: raise DirNotFoundError(n) perm = inodetable.S_IWUSR | inodetable.S_IWGRP | inodetable.S_IWOTH if not permissions.check_file_permissions(dir_inodetable_block, dir_in, perm): raise permissions.PermissionsError(perm) offset = filerecord.find_file_record(dir_inodetable_block, dir_table_in, names[-1]) if offset is None: filerecord.create_file_record(dir_inodetable_block, dir_table_in, inode_n, names[-1]) dir_inodetable_block.set_field(dir_table_in, dir_inodetable_block.i_mtime, int(time.time())) else: raise FileAlreadyExistsError(names[-1]) inodetable_block = inodetable.load_inode(inode_n) inodetable_block.set_field(inode_ign, inodetable_block.i_mode, mode) inodetable_block.set_field(inode_ign, inodetable_block.i_uid, user.get_uid()) inodetable_block.set_field(inode_ign, inodetable_block.i_size, 0) inodetable_block.set_field(inode_ign, inodetable_block.i_atime, 0) inodetable_block.set_field(inode_ign, inodetable_block.i_mtime, 0) inodetable_block.set_field(inode_ign, inodetable_block.i_ctime, int(time.time())) inodetable_block.set_field(inode_ign, inodetable_block.i_dtime, 0) inodetable_block.set_field(inode_ign, inodetable_block.i_gid, user.get_gid()) inodetable_block.set_field(inode_ign, inodetable_block.i_blocks, 0) inodetable_block.set_field(inode_ign, inodetable_block.i_flags, 0) inodetable_block.set_field(inode_ign, inodetable_block.i_block, bytes(60)) inodetable_block.set_field( inode_ign, inodetable_block.i_pad, bytes(inodetable_block.i_pad[sysblock.SIZE_INDEX])) inodebitmap.set_used_inode(inode_ign) inodebitmap.inode_bitmap.unload( fs.bytes_to_int(bg_block.get_field(0, bg_block.bg_inode_bitmap))) inodetable.unload_inode(inode_n) inodetable.unload_inode(0) return fdtable.reserve_fd(inode_n)
def load(self, block_number): if self.block_size is None: self.block_size = fs.bytes_to_int( superblock.get_field(superblock.s_log_block_size)) * 1024 self.block_number = block_number self.block_buffer = bytearray(balloc.read_block(block_number))
def get_gdtableblock(index): bn = index * fs.GD_SIZE // (fs.bytes_to_int(superblock.get_field(superblock.s_log_block_size)) * 1024) return gdtable_blocks[bn]
def get_group_number(number): return number // fs.bytes_to_int(superblock.get_field(superblock.s_inodes_per_group))