static int extend(int input) { struct pstore_header *header; unsigned long ndx; off_t f_end; header = pstore_header_read(input); seek_or_die(input, 0, SEEK_END); for (ndx = 0; ndx < header->nr_tables; ndx++) { struct pstore_table *table = header->tables[ndx]; if (pstore_table_matches(table, table_ref)) { if (extend_table(table, input) < 0) return -1; } } f_end = seek_or_die(input, 0, SEEK_CUR); /* * Write out the header again because offsets to last extents changed. */ seek_or_die(input, 0, SEEK_SET); if (pstore_header_write(header, input) < 0) die("pstore_header_write"); pstore_header_delete(header); seek_or_die(input, f_end, SEEK_SET); return 0; }
/* Reads a snapshot record from a qcow2-formatted file. * * The function assumes the file position of 'fd' points to the beginning of a * QcowSnapshotHeader record. When the call returns, the file position of fd is * at the place where the next QcowSnapshotHeader should start, if there is one. * * C.f. QCowSnapshotHeader in block/qcow2-snapshot.c for the complete layout of * the header. */ static void snapshot_info_read( int fd, SnapshotInfo* info ) { uint64_t start_offset = seek_or_die(fd, 0, SEEK_CUR); uint32_t extra_data_size; uint16_t id_str_size, name_size; /* read fixed-length fields */ seek_or_die(fd, 12, SEEK_CUR); /* skip l1 info */ read_or_die(fd, &id_str_size, sizeof(id_str_size)); read_or_die(fd, &name_size, sizeof(name_size)); read_or_die(fd, &info->date_sec, sizeof(info->date_sec)); read_or_die(fd, &info->date_nsec, sizeof(info->date_nsec)); read_or_die(fd, &info->vm_clock_nsec, sizeof(info->vm_clock_nsec)); read_or_die(fd, &info->vm_state_size, sizeof(info->vm_state_size)); read_or_die(fd, &extra_data_size, sizeof(extra_data_size)); /* convert to host endianness */ be16_to_cpus(&id_str_size); be16_to_cpus(&name_size); be32_to_cpus(&info->date_sec); be32_to_cpus(&info->date_nsec); be64_to_cpus(&info->vm_clock_nsec); be32_to_cpus(&info->vm_state_size); be32_to_cpus(&extra_data_size); be32_to_cpus(&extra_data_size); /* read variable-length buffers*/ info->id_str = android_alloc(id_str_size + 1); // +1: manual null-termination info->name = android_alloc(name_size + 1); seek_or_die(fd, extra_data_size, SEEK_CUR); /* skip extra data */ read_or_die(fd, info->id_str, id_str_size); read_or_die(fd, info->name, name_size); info->id_str[id_str_size] = '\0'; info->name[name_size] = '\0'; /* headers are 8 byte aligned, ceil to nearest multiple of 8 */ uint64_t end_offset = seek_or_die(fd, 0, SEEK_CUR); uint32_t total_size = end_offset - start_offset; uint32_t aligned_size = ((total_size - 1) / 8 + 1) * 8; /* skip to start of next record */ seek_or_die(fd, start_offset + aligned_size, SEEK_SET); }
static int extend_column(struct pstore_column *column, int input) { struct pstore_extent *extent; off_t offset; offset = seek_or_die(input, 0, SEEK_CUR); extent = pstore_extent_read(column, column->last_extent, input); column->prev_extent = extent; column->extent = pstore_extent_new(column, PSTORE_COMP_NONE); seek_or_die(input, offset, SEEK_SET); if (pstore_column_preallocate(column, input, extent_len) < 0) return -1; if (pstore_extent_write_metadata(column->extent, PSTORE_LAST_EXTENT, input) < 0) return -1; return 0; }
int cmd_extend(int argc, char *argv[]) { int input; off_t f_size; if (argc < 3) usage(); parse_args(argc - 1, argv + 1); input = open(input_file, O_RDWR); if (input < 0) die("Failed to open input file '%s': %s", input_file, strerror(errno)); f_size = seek_or_die(input, 0, SEEK_END); if (posix_fallocate(input, f_size, extent_len) != 0) die("posix_fallocate"); seek_or_die(input, 0, SEEK_SET); if (extend(input) < 0) die("extend failed"); f_size = seek_or_die(input, 0, SEEK_CUR); if (ftruncate(input, f_size) != 0) die("ftruncate"); if (fsync(input) < 0) die("fsync"); if (close(input) < 0) die("close"); return 0; }