Skip to content

Commit 663ab8d

Browse files
committed
create: implements create empty image
Signed-off-by: Koichi Shiraishi <[email protected]>
1 parent 62788fc commit 663ab8d

18 files changed

+1820
-497
lines changed

Makefile

+14-1
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,24 @@ IGNORE_FILE = $(foreach file,Makefile,--ignore $(file))
22
IGNORE_DIR = $(foreach dir,vendor testdata internal,--ignore-dir $(dir))
33
IGNORE = $(IGNORE_FILE) $(IGNORE_DIR)
44

5+
all: test
6+
7+
install:
8+
go install -v -x ./...
9+
10+
install-force:
11+
rm -rf $(GOPATH)/pkg/darwin_amd64/github.com/zchee/go-qcow2 $(GOPATH)/pkg/darwin_amd64/github.com/zchee/go-qcow2.a
12+
go install -v -x ./...
13+
14+
test:
15+
go run cmd/qcow-test/qcow-test.go
16+
readbyte search testdata/test.qcow2
17+
518
todo:
619
@ag 'TODO(\(.+\):|:)' --after=1 $(IGNORE) || true
720
@ag 'BUG(\(.+\):|:)' --after=1 $(IGNORE)|| true
821
@ag 'XXX(\(.+\):|:)' --after=1 $(IGNORE)|| true
922
@ag 'FIXME(\(.+\):|:)' --after=1 $(IGNORE) || true
1023
@ag 'NOTE(\(.+\):|:)' --after=1 $(IGNORE) || true
1124

12-
.PHONY: todo
25+
.PHONY: todo test install

block.go

+2-49
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ package qcow2
66

77
import (
88
"bytes"
9-
"log"
109
"os"
1110
)
1211

@@ -27,52 +26,6 @@ type BlockBackend struct {
2726
Error error
2827
}
2928

30-
// Open open the QCow2 block-backend image file.
31-
func (blk *BlockBackend) Open(filename, reference string, options *BlockOption, flag int) error {
32-
file, err := os.OpenFile(filename, flag, os.FileMode(0))
33-
if err != nil {
34-
return err
35-
}
36-
37-
blk.File = file
38-
39-
return nil
40-
}
41-
42-
func PrintByte(buf []byte) {
43-
log.Println(buf)
44-
log.Printf(" [0:3] Magic: %+v", buf[:4])
45-
log.Printf(" [4:7] Version: %+v", buf[4:8])
46-
log.Printf(" [8:15] BackingFileOffset: %+v", buf[8:16])
47-
log.Printf(" [16:19] BackingFileSize: %+v", buf[16:20])
48-
log.Printf(" [20:23] ClusterBits: %+v", buf[20:24])
49-
log.Printf(" [24:31] Size: %+v", buf[24:32])
50-
log.Printf(" [32:35] CryptMethod: %+v", buf[32:36])
51-
log.Printf(" [36:39] L1Size: %+v", buf[36:40])
52-
log.Printf(" [40:47] L1TableOffset: %+v", buf[40:48])
53-
log.Printf(" [48:55] RefcountTableOffset: %+v", buf[48:56])
54-
log.Printf(" [56:59] RefcountTableClusters: %+v", buf[56:60])
55-
log.Printf(" [60:63] NbSnapshots: %+v", buf[60:64])
56-
log.Printf(" [64:71] SnapshotsOffset: %+v", buf[64:72])
57-
log.Printf(" [72:79] IncompatibleFeatures: %+v", buf[72:80])
58-
log.Printf(" [80:87] CompatibleFeatures: %+v", buf[80:88])
59-
log.Printf(" [88:95] AutoclearFeatures: %+v", buf[88:96])
60-
log.Printf(" [96:99] RefcountOrder: %+v", buf[96:100])
61-
log.Printf("[101:105] HeaderLength: %+v", buf[100:104])
62-
63-
log.Printf("[106:109] HeaderExtensionType: %+v", buf[104:108])
64-
log.Printf("[110:114] HeaderExtensionLength: %+v", buf[108:112])
65-
log.Printf("[115:162] HeaderExtensionData: %+v", buf[112:158])
66-
67-
log.Printf("[163:166] HeaderExtensionType: %+v", buf[158:162])
68-
log.Printf("[167:171] HeaderExtensionLength: %+v", buf[162:166])
69-
log.Printf("[172:219] HeaderExtensionData: %+v", buf[166:212])
70-
71-
log.Printf("[220:223] HeaderExtensionType: %+v", buf[212:216])
72-
log.Printf("[224:228] HeaderExtensionLength: %+v", buf[216:220])
73-
log.Printf("[229:276] HeaderExtensionData: %+v", buf[220:266])
74-
75-
if len(buf) > 266 {
76-
log.Printf("[277:] Other: %+v", buf[277:len(buf)-1])
77-
}
29+
func (blk *BlockBackend) bs() *BlockDriverState {
30+
return blk.BlockDriverState
7831
}

cfunc.go

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// Copyright 2016 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package qcow2
6+
7+
/*
8+
#include <stdint.h>
9+
#include <stdlib.h>
10+
11+
static inline int ctz32(uint32_t val)
12+
{
13+
// Binary search for the trailing one bit
14+
int cnt;
15+
16+
cnt = 0;
17+
if (!(val & 0x0000FFFFUL)) {
18+
cnt += 16;
19+
val >>= 16;
20+
}
21+
if (!(val & 0x000000FFUL)) {
22+
cnt += 8;
23+
val >>= 8;
24+
}
25+
if (!(val & 0x0000000FUL)) {
26+
cnt += 4;
27+
val >>= 4;
28+
}
29+
if (!(val & 0x00000003UL)) {
30+
cnt += 2;
31+
val >>= 2;
32+
}
33+
if (!(val & 0x00000001UL)) {
34+
cnt++;
35+
val >>= 1;
36+
}
37+
if (!(val & 0x00000001UL)) {
38+
cnt++;
39+
}
40+
41+
return cnt;
42+
}
43+
*/
44+
import "C"
45+
import "unsafe"
46+
47+
func ctz32(val uint32) int {
48+
i := C.ctz32(C.uint32_t(val))
49+
return int(i)
50+
}
51+
52+
func posixMemalign(alignment uint64, size uint64) []byte {
53+
var ptr C.void
54+
ptr2 := unsafe.Pointer(&ptr)
55+
C.posix_memalign(&ptr2, C.size_t(uintptr(alignment)), C.size_t(uintptr(size)))
56+
return []byte(C.GoBytes(unsafe.Pointer(&ptr), C.int(C.size_t(size))))
57+
}

cluster.go

+116
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
// Copyright 2016 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package qcow2
6+
7+
import (
8+
"log"
9+
"syscall"
10+
11+
"github.com/zchee/go-qcow2/internal/mem"
12+
)
13+
14+
const DEBUG_ALLOC2 = false
15+
16+
func growL1Table(bs *BlockDriverState, minSize uint64, exactSize bool) error {
17+
s := bs.Opaque
18+
var newL1Size int64
19+
20+
if minSize <= uint64(s.L1Size) {
21+
return nil
22+
}
23+
24+
// Do a sanity check on min_size before trying to calculate new_l1_size
25+
// (this prevents overflows during the while loop for the calculation of
26+
// new_l1_size)
27+
if minSize > INT_MAX/UINT64_SIZE {
28+
return syscall.EFBIG
29+
}
30+
31+
if exactSize {
32+
newL1Size = int64(minSize)
33+
} else {
34+
// Bump size up to reduce the number of times we have to grow
35+
newL1Size = int64(s.L1Size)
36+
if newL1Size == 0 {
37+
newL1Size = 1
38+
}
39+
for minSize > uint64(newL1Size) {
40+
newL1Size = (newL1Size*3 + 1) / 2
41+
}
42+
}
43+
44+
if newL1Size > MAX_L1_SIZE/UINT64_SIZE {
45+
return syscall.EFBIG
46+
}
47+
48+
log.Printf("grow l1_table from %d to %d\n", s.L1Size, newL1Size)
49+
50+
newL1Size2 := UINT64_SIZE * newL1Size
51+
log.Printf("newL1Size2: %+v\n", newL1Size2)
52+
align := bdrvOptMemAlign(bs)
53+
newL1Table := posixMemalign(uint64(align), uint64(alignOffset(newL1Size2, 512)))
54+
log.Printf("newL1Table: %+v\n", newL1Table)
55+
if newL1Table == nil {
56+
return syscall.ENOMEM
57+
}
58+
mem.Set(newL1Table, byte(alignOffset(newL1Size2, 512)))
59+
60+
mem.Cpy(newL1Table, []byte{byte(s.L1Table)}, uintptr(s.L1Size*UINT64_SIZE))
61+
62+
// write new table (align to cluster)
63+
newL1TableOffset, err := AllocClusters(bs, uint64(newL1Size2))
64+
if err != nil {
65+
return err
66+
}
67+
log.Printf("newL1TableOffset: %+v\n", newL1TableOffset)
68+
69+
// ret = qcow2_cache_flush(bs, s->refcount_block_cache);
70+
// if (ret < 0) {
71+
// goto fail;
72+
// }
73+
//
74+
// /* the L1 position has not yet been updated, so these clusters must
75+
// * indeed be completely free */
76+
// ret = qcow2_pre_write_overlap_check(bs, 0, new_l1_table_offset,
77+
// new_l1_size2);
78+
// if (ret < 0) {
79+
// goto fail;
80+
// }
81+
//
82+
// BLKDBG_EVENT(bs->file, BLKDBG_L1_GROW_WRITE_TABLE);
83+
// for(i = 0; i < s->l1_size; i++)
84+
// new_l1_table[i] = cpu_to_be64(new_l1_table[i]);
85+
// ret = bdrv_pwrite_sync(bs->file, new_l1_table_offset,
86+
// new_l1_table, new_l1_size2);
87+
// if (ret < 0)
88+
// goto fail;
89+
// for(i = 0; i < s->l1_size; i++)
90+
// new_l1_table[i] = be64_to_cpu(new_l1_table[i]);
91+
//
92+
// /* set new table */
93+
// BLKDBG_EVENT(bs->file, BLKDBG_L1_GROW_ACTIVATE_TABLE);
94+
// stl_be_p(data, new_l1_size);
95+
// stq_be_p(data + 4, new_l1_table_offset);
96+
// ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, l1_size),
97+
// data, sizeof(data));
98+
// if (ret < 0) {
99+
// goto fail;
100+
// }
101+
// qemu_vfree(s->l1_table);
102+
// old_l1_table_offset = s->l1_table_offset;
103+
// s->l1_table_offset = new_l1_table_offset;
104+
// s->l1_table = new_l1_table;
105+
// old_l1_size = s->l1_size;
106+
// s->l1_size = new_l1_size;
107+
// qcow2_free_clusters(bs, old_l1_table_offset, old_l1_size * sizeof(uint64_t),
108+
// QCOW2_DISCARD_OTHER);
109+
// return 0;
110+
// fail:
111+
// qemu_vfree(new_l1_table);
112+
// qcow2_free_clusters(bs, new_l1_table_offset, new_l1_size2,
113+
// QCOW2_DISCARD_OTHER);
114+
// return ret;
115+
return nil
116+
}

0 commit comments

Comments
 (0)