static int vhd_read_data(vhd_context_t *vhd, uint64_t sec, int count, int hex) { void *buf; uint64_t cur; int err, max, secs; if (vhd_sectors_to_bytes(sec + count) > vhd->footer.curr_size) return -ERANGE; max = MIN(vhd_sectors_to_bytes(count), VHD_BLOCK_SIZE); err = posix_memalign(&buf, VHD_SECTOR_SIZE, max); if (err) return -err; cur = sec; while (count) { int gcc; secs = MIN((max >> VHD_SECTOR_SHIFT), count); err = vhd_io_read(vhd, buf, cur, secs); if (err) break; gcc = write(STDOUT_FILENO, buf, vhd_sectors_to_bytes(secs)); if (gcc) ; cur += secs; count -= secs; } free(buf); return err; }
static int vhd_print_logical_to_physical(vhd_context_t *vhd, uint64_t sector, int count, int hex) { int i; uint32_t blk, lsec; uint64_t cur, offset; if (vhd_sectors_to_bytes(sector + count) > vhd->footer.curr_size) { fprintf(stderr, "sector %s past end of file\n", conv(hex, sector + count)); return -ERANGE; } for (i = 0; i < count; i++) { cur = sector + i; blk = cur / vhd->spb; lsec = cur % vhd->spb; offset = vhd->bat.bat[blk]; if (offset != DD_BLK_UNUSED) { offset += lsec + 1; offset = vhd_sectors_to_bytes(offset); } printf("logical sector %s: ", conv(hex, cur)); printf("block number: %s, ", conv(hex, blk)); printf("sector offset: %s, ", conv(hex, lsec)); printf("file offset: %s\n", (offset == DD_BLK_UNUSED ? "not allocated" : conv(hex, offset))); } return 0; }
static int vhd_index_schedule_meta_read(vhd_index_t *index, uint32_t blk) { int err; off64_t offset; vhd_index_block_t *block; vhd_index_request_t *req; ASSERT(index->bat.table[blk] != DD_BLK_UNUSED); block = vhd_index_get_block(index, blk); if (!block) { err = vhd_index_install_block(index, &block, blk); if (err) return err; } offset = vhd_sectors_to_bytes(index->bat.table[blk]); req = &block->req; req->index = index; req->treq.sec = blk * index->vhdi.spb; req->treq.secs = block->table_size >> VHD_SECTOR_SHIFT; td_prep_read(&req->tiocb, index->vhdi.fd, (char *)block->vhdi_block.table, block->table_size, offset, vhd_index_complete_meta_read, req); td_queue_tiocb(index->driver, &req->tiocb); td_flag_set(block->state, VHD_INDEX_BLOCK_READ_PENDING); return 0; }
static int vhd_journal_read_batmap_map(vhd_journal_t *j, vhd_batmap_t *batmap) { int err; vhd_journal_entry_t entry; void *map; err = vhd_journal_read_entry(j, &entry); if (err) return err; if (entry.type != VHD_JOURNAL_ENTRY_TYPE_BATMAP_M) return -EINVAL; if (entry.size != vhd_sectors_to_bytes(batmap->header.batmap_size)) return -EINVAL; if (entry.offset != batmap->header.batmap_offset) return -EINVAL; err = posix_memalign(&map, VHD_SECTOR_SIZE, entry.size); if (err) return -err; batmap->map = map; err = vhd_journal_read(j, batmap->map, entry.size); if (err) { free(batmap->map); batmap->map = NULL; return err; } return 0; }
static int vhd_index_schedule_data_read(vhd_index_t *index, td_request_t treq) { int i, err; size_t size; off64_t offset; uint32_t blk, sec; vhd_index_block_t *block; vhd_index_request_t *req; vhd_index_file_ref_t *file; blk = treq.sec / index->vhdi.spb; sec = treq.sec % index->vhdi.spb; block = vhd_index_get_block(index, blk); ASSERT(block && vhd_index_block_valid(block)); for (i = 0; i < treq.secs; i++) { ASSERT(block->vhdi_block.table[sec + i].file_id != 0); ASSERT(block->vhdi_block.table[sec + i].offset != DD_BLK_UNUSED); } req = vhd_index_allocate_request(index); if (!req) return -EBUSY; err = vhd_index_get_file(index, block->vhdi_block.table[sec].file_id, &file); if (err) { vhd_index_free_request(index, req); return err; } size = vhd_sectors_to_bytes(treq.secs); offset = vhd_sectors_to_bytes(block->vhdi_block.table[sec].offset); req->file = file; req->treq = treq; req->index = index; req->off = offset; td_prep_read(&req->tiocb, file->fd, treq.buf, size, offset, vhd_index_complete_data_read, req); td_queue_tiocb(index->driver, &req->tiocb); return 0; }
static int vhd_test_bitmap(vhd_context_t *vhd, uint64_t sector, int count, int hex) { char *buf; uint64_t cur; int i, err, bit; uint32_t blk, bm_blk, sec; if (vhd_sectors_to_bytes(sector + count) > vhd->footer.curr_size) { printf("sector %s past end of file\n", conv(hex, sector)); return -ERANGE; } bm_blk = -1; buf = NULL; for (i = 0; i < count; i++) { cur = sector + i; blk = cur / vhd->spb; sec = cur % vhd->spb; if (blk != bm_blk) { bm_blk = blk; free(buf); buf = NULL; if (vhd->bat.bat[blk] != DD_BLK_UNUSED) { err = vhd_read_bitmap(vhd, blk, &buf); if (err) goto out; } } if (vhd->bat.bat[blk] == DD_BLK_UNUSED) bit = 0; else bit = vhd_bitmap_test(vhd, buf, sec); printf("block %s: ", conv(hex, blk)); printf("sec: %s: %d\n", conv(hex, sec), bit); } err = 0; out: free(buf); return err; }
static int vhd_print_batmap(vhd_context_t *vhd) { int err, gcc; size_t size; err = vhd_get_batmap(vhd); if (err) { printf("failed to read batmap: %d\n", err); return err; } size = vhd_sectors_to_bytes(vhd->batmap.header.batmap_size); gcc = write(STDOUT_FILENO, vhd->batmap.map, size); if (gcc) ; return 0; }
static int vhd_print_bat(vhd_context_t *vhd, uint64_t block, int count, int hex) { int i; uint64_t cur, offset; if (check_block_range(vhd, block + count, hex)) return -ERANGE; for (i = 0; i < count && i < vhd->bat.entries; i++) { cur = block + i; offset = vhd->bat.bat[cur]; printf("block: %s: ", conv(hex, cur)); printf("offset: %s\n", (offset == DD_BLK_UNUSED ? "not allocated" : conv(hex, vhd_sectors_to_bytes(offset)))); } return 0; }
static int vhd_journal_add_batmap(vhd_journal_t *j) { int err; off64_t off; size_t size; vhd_context_t *vhd; vhd_batmap_t batmap; vhd = &j->vhd; err = vhd_batmap_header_offset(vhd, &off); if (err) return err; err = vhd_read_batmap(vhd, &batmap); if (err) return err; size = vhd_bytes_padded(sizeof(struct dd_batmap_hdr)); vhd_batmap_header_out(&batmap); err = vhd_journal_update(j, off, (char *)&batmap.header, size, VHD_JOURNAL_ENTRY_TYPE_BATMAP_H); if (err) goto out; vhd_batmap_header_in(&batmap); off = batmap.header.batmap_offset; size = vhd_sectors_to_bytes(batmap.header.batmap_size); err = vhd_journal_update(j, off, batmap.map, size, VHD_JOURNAL_ENTRY_TYPE_BATMAP_M); out: free(batmap.map); return err; }
static int vhd_print_bitmap(vhd_context_t *vhd, uint64_t block, int count, int hex) { char *buf; int i, err; uint64_t cur; ssize_t n; if (check_block_range(vhd, block + count, hex)) return -ERANGE; for (i = 0; i < count; i++) { cur = block + i; if (vhd->bat.bat[cur] == DD_BLK_UNUSED) { printf("block %s not allocated\n", conv(hex, cur)); continue; } err = vhd_read_bitmap(vhd, cur, &buf); if (err) goto out; n = write(STDOUT_FILENO, buf, vhd_sectors_to_bytes(vhd->bm_secs)); if (n < 0) { err = -errno; goto out; } free(buf); } err = 0; out: return err; }
static void vhd_index_queue_read(td_driver_t *driver, td_request_t treq) { vhd_index_t *index; index = (vhd_index_t *)driver->data; while (treq.secs) { int err; td_request_t clone; err = 0; clone = treq; switch (vhd_index_read_cache(index, clone.sec)) { case -EINVAL: err = -EINVAL; goto fail; case VHD_INDEX_BAT_CLEAR: clone.secs = MIN(clone.secs, index->vhdi.spb - (clone.sec % index->vhdi.spb)); td_forward_request(clone); break; case VHD_INDEX_BIT_CLEAR: clone.secs = vhd_index_read_cache_span(index, clone.sec, clone.secs, 0); td_forward_request(clone); break; case VHD_INDEX_BIT_SET: clone.secs = vhd_index_read_cache_span(index, clone.sec, clone.secs, 1); err = vhd_index_schedule_data_read(index, clone); if (err) goto fail; break; case VHD_INDEX_CACHE_MISS: err = vhd_index_schedule_meta_read(index, clone.sec / index->vhdi.spb); if (err) goto fail; clone.secs = MIN(clone.secs, index->vhdi.spb - (clone.sec % index->vhdi.spb)); vhd_index_queue_request(index, clone); break; case VHD_INDEX_META_READ_PENDING: clone.secs = MIN(clone.secs, index->vhdi.spb - (clone.sec % index->vhdi.spb)); err = vhd_index_queue_request(index, clone); if (err) goto fail; break; } treq.sec += clone.secs; treq.secs -= clone.secs; treq.buf += vhd_sectors_to_bytes(clone.secs); continue; fail: clone.secs = treq.secs; td_complete_request(clone, err); break; } }
int vhd_journal_add_block(vhd_journal_t *j, uint32_t block, char mode) { int err; char *buf; off64_t off; size_t size; uint64_t blk; vhd_context_t *vhd; buf = NULL; vhd = &j->vhd; if (!vhd_type_dynamic(vhd)) return -EINVAL; err = vhd_get_bat(vhd); if (err) return err; if (block >= vhd->bat.entries) return -ERANGE; blk = vhd->bat.bat[block]; if (blk == DD_BLK_UNUSED) return 0; off = vhd_sectors_to_bytes(blk); if (mode & VHD_JOURNAL_METADATA) { size = vhd_sectors_to_bytes(vhd->bm_secs); err = vhd_read_bitmap(vhd, block, &buf); if (err) return err; err = vhd_journal_update(j, off, buf, size, VHD_JOURNAL_ENTRY_TYPE_DATA); free(buf); if (err) return err; } if (mode & VHD_JOURNAL_DATA) { off += vhd_sectors_to_bytes(vhd->bm_secs); size = vhd_sectors_to_bytes(vhd->spb); err = vhd_read_block(vhd, block, &buf); if (err) return err; err = vhd_journal_update(j, off, buf, size, VHD_JOURNAL_ENTRY_TYPE_DATA); free(buf); if (err) return err; } return vhd_journal_sync(j); }