1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24: #include "qemu-common.h"
25: #include "block_int.h"
26: #include <zlib.h>
27:
28: typedef struct BDRVCloopState {
29: int fd;
30: uint32_t block_size;
31: uint32_t n_blocks;
32: uint64_t* offsets;
33: uint32_t sectors_per_block;
34: uint32_t current_block;
35: uint8_t *compressed_block;
36: uint8_t *uncompressed_block;
37: z_stream zstream;
38: } BDRVCloopState;
39:
40: static int cloop_probe(const uint8_t *buf, int buf_size, const char *filename)
41: {
42: const char* magic_version_2_0="#!/bin/sh\n"
43: "#V2.0 Format\n"
44: "modprobe cloop file=$0 && mount -r -t iso9660 /dev/cloop $1\n";
45: int length=strlen(magic_version_2_0);
46: if(length>buf_size)
47: length=buf_size;
48: if(!memcmp(magic_version_2_0,buf,length))
49: return 2;
50: return 0;
51: }
52:
53: static int cloop_open(BlockDriverState *bs, const char *filename, int flags)
54: {
55: BDRVCloopState *s = bs->opaque;
56: uint32_t offsets_size,max_compressed_block_size=1,i;
57:
58: s->fd = open(filename, O_RDONLY | O_BINARY);
59: if (s->fd < 0)
60: return -errno;
61: bs->read_only = 1;
62:
63:
64: if(lseek(s->fd,128,SEEK_SET)<0) {
65: cloop_close:
66: close(s->fd);
67: return -1;
68: }
69: if(read(s->fd,&s->block_size,4)<4)
70: goto cloop_close;
71: s->block_size=be32_to_cpu(s->block_size);
72: if(read(s->fd,&s->n_blocks,4)<4)
73: goto cloop_close;
74: s->n_blocks=be32_to_cpu(s->n_blocks);
75:
76:
77: offsets_size=s->n_blocks*sizeof(uint64_t);
78: if(!(s->offsets=(uint64_t*)malloc(offsets_size)))
79: goto cloop_close;
80: if(read(s->fd,s->offsets,offsets_size)<offsets_size)
81: goto cloop_close;
82: for(i=0;i<s->n_blocks;i++) {
83: s->offsets[i]=be64_to_cpu(s->offsets[i]);
84: if(i>0) {
85: uint32_t size=s->offsets[i]-s->offsets[i-1];
86: if(size>max_compressed_block_size)
87: max_compressed_block_size=size;
88: }
89: }
90:
91:
92: if(!(s->compressed_block = malloc(max_compressed_block_size+1)))
93: goto cloop_close;
94: if(!(s->uncompressed_block = malloc(s->block_size)))
95: goto cloop_close;
96: if(inflateInit(&s->zstream) != Z_OK)
97: goto cloop_close;
98: s->current_block=s->n_blocks;
99:
100: s->sectors_per_block = s->block_size/512;
101: bs->total_sectors = s->n_blocks*s->sectors_per_block;
102: return 0;
103: }
104:
105: static inline int cloop_read_block(BDRVCloopState *s,int block_num)
106: {
107: if(s->current_block != block_num) {
108: int ret;
109: uint32_t bytes = s->offsets[block_num+1]-s->offsets[block_num];
110:
111: lseek(s->fd, s->offsets[block_num], SEEK_SET);
112: ret = read(s->fd, s->compressed_block, bytes);
113: if (ret != bytes)
114: return -1;
115:
116: s->zstream.next_in = s->compressed_block;
117: s->zstream.avail_in = bytes;
118: s->zstream.next_out = s->uncompressed_block;
119: s->zstream.avail_out = s->block_size;
120: ret = inflateReset(&s->zstream);
121: if(ret != Z_OK)
122: return -1;
123: ret = inflate(&s->zstream, Z_FINISH);
124: if(ret != Z_STREAM_END || s->zstream.total_out != s->block_size)
125: return -1;
126:
127: s->current_block = block_num;
128: }
129: return 0;
130: }
131:
132: static int cloop_read(BlockDriverState *bs, int64_t sector_num,
133: uint8_t *buf, int nb_sectors)
134: {
135: BDRVCloopState *s = bs->opaque;
136: int i;
137:
138: for(i=0;i<nb_sectors;i++) {
139: uint32_t sector_offset_in_block=((sector_num+i)%s->sectors_per_block),
140: block_num=(sector_num+i)/s->sectors_per_block;
141: if(cloop_read_block(s, block_num) != 0)
142: return -1;
143: memcpy(buf+i*512,s->uncompressed_block+sector_offset_in_block*512,512);
144: }
145: return 0;
146: }
147:
148: static void cloop_close(BlockDriverState *bs)
149: {
150: BDRVCloopState *s = bs->opaque;
151: close(s->fd);
152: if(s->n_blocks>0)
153: free(s->offsets);
154: free(s->compressed_block);
155: free(s->uncompressed_block);
156: inflateEnd(&s->zstream);
157: }
158:
159: BlockDriver bdrv_cloop = {
160: "cloop",
161: sizeof(BDRVCloopState),
162: cloop_probe,
163: cloop_open,
164: cloop_read,
165: NULL,
166: cloop_close,
167: };
168:
169: