(linenum→info "unix/slp.c:2238")

qemu/0.9.1/block-dmg.c

    1: /*
    2:  * QEMU Block driver for DMG images
    3:  *
    4:  * Copyright (c) 2004 Johannes E. Schindelin
    5:  *
    6:  * Permission is hereby granted, free of charge, to any person obtaining a copy
    7:  * of this software and associated documentation files (the "Software"), to deal
    8:  * in the Software without restriction, including without limitation the rights
    9:  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   10:  * copies of the Software, and to permit persons to whom the Software is
   11:  * furnished to do so, subject to the following conditions:
   12:  *
   13:  * The above copyright notice and this permission notice shall be included in
   14:  * all copies or substantial portions of the Software.
   15:  *
   16:  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   17:  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   18:  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
   19:  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   20:  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   21:  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
   22:  * THE SOFTWARE.
   23:  */
   24: #include "qemu-common.h"
   25: #include "block_int.h"
   26: #include "bswap.h"
   27: #include <zlib.h>
   28: 
   29: typedef struct BDRVDMGState {
   30:     int fd;
   31: 
   32:     /* each chunk contains a certain number of sectors,
   33:      * offsets[i] is the offset in the .dmg file,
   34:      * lengths[i] is the length of the compressed chunk,
   35:      * sectors[i] is the sector beginning at offsets[i],
   36:      * sectorcounts[i] is the number of sectors in that chunk,
   37:      * the sectors array is ordered
   38:      * 0<=i<n_chunks */
   39: 
   40:     uint32_t n_chunks;
   41:     uint32_t* types;
   42:     uint64_t* offsets;
   43:     uint64_t* lengths;
   44:     uint64_t* sectors;
   45:     uint64_t* sectorcounts;
   46:     uint32_t current_chunk;
   47:     uint8_t *compressed_chunk;
   48:     uint8_t *uncompressed_chunk;
   49:     z_stream zstream;
   50: } BDRVDMGState;
   51: 
   52: static int dmg_probe(const uint8_t *buf, int buf_size, const char *filename)
   53: {
   54:     int len=strlen(filename);
   55:     if(len>4 && !strcmp(filename+len-4,".dmg"))
   56:         return 2;
   57:     return 0;
   58: }
   59: 
   60: static off_t read_off(int fd)
   61: {
   62:         uint64_t buffer;
   63:         if(read(fd,&buffer,8)<8)
   64:                 return 0;
   65:         return be64_to_cpu(buffer);
   66: }
   67: 
   68: static off_t read_uint32(int fd)
   69: {
   70:         uint32_t buffer;
   71:         if(read(fd,&buffer,4)<4)
   72:                 return 0;
   73:         return be32_to_cpu(buffer);
   74: }
   75: 
   76: static int dmg_open(BlockDriverState *bs, const char *filename, int flags)
   77: {
   78:     BDRVDMGState *s = bs->opaque;
   79:     off_t info_begin,info_end,last_in_offset,last_out_offset;
   80:     uint32_t count;
   81:     uint32_t max_compressed_size=1,max_sectors_per_chunk=1,i;
   82: 
   83:     s->fd = open(filename, O_RDONLY | O_BINARY);
   84:     if (s->fd < 0)
   85:         return -errno;
   86:     bs->read_only = 1;
   87:     s->n_chunks = 0;
   88:     s->offsets = s->lengths = s->sectors = s->sectorcounts = 0;
   89: 
   90:     /* read offset of info blocks */
   91:     if(lseek(s->fd,-0x1d8,SEEK_END)<0) {
   92: dmg_close:
   93:         close(s->fd);
   94:         /* open raw instead */
   95:         bs->drv=&bdrv_raw;
   96:         return bs->drv->bdrv_open(bs, filename, flags);
   97:     }
   98:     info_begin=read_off(s->fd);
   99:     if(info_begin==0)
  100:         goto dmg_close;
  101:     if(lseek(s->fd,info_begin,SEEK_SET)<0)
  102:         goto dmg_close;
  103:     if(read_uint32(s->fd)!=0x100)
  104:         goto dmg_close;
  105:     if((count = read_uint32(s->fd))==0)
  106:         goto dmg_close;
  107:     info_end = info_begin+count;
  108:     if(lseek(s->fd,0xf8,SEEK_CUR)<0)
  109:         goto dmg_close;
  110: 
  111:     /* read offsets */
  112:     last_in_offset = last_out_offset = 0;
  113:     while(lseek(s->fd,0,SEEK_CUR)<info_end) {
  114:         uint32_t type;
  115: 
  116:         count = read_uint32(s->fd);
  117:         if(count==0)
  118:             goto dmg_close;
  119:         type = read_uint32(s->fd);
  120:         if(type!=0x6d697368 || count<244)
  121:             lseek(s->fd,count-4,SEEK_CUR);
  122:         else {
  123:             int new_size, chunk_count;
  124:             if(lseek(s->fd,200,SEEK_CUR)<0)
  125:                 goto dmg_close;
  126:             chunk_count = (count-204)/40;
  127:             new_size = sizeof(uint64_t) * (s->n_chunks + chunk_count);
  128:             s->types = realloc(s->types, new_size/2);
  129:             s->offsets = realloc(s->offsets, new_size);
  130:             s->lengths = realloc(s->lengths, new_size);
  131:             s->sectors = realloc(s->sectors, new_size);
  132:             s->sectorcounts = realloc(s->sectorcounts, new_size);
  133: 
  134:             for(i=s->n_chunks;i<s->n_chunks+chunk_count;i++) {
  135:                 s->types[i] = read_uint32(s->fd);
  136:                 if(s->types[i]!=0x80000005 && s->types[i]!=1 && s->types[i]!=2) {
  137:                     if(s->types[i]==0xffffffff) {
  138:                         last_in_offset = s->offsets[i-1]+s->lengths[i-1];
  139:                         last_out_offset = s->sectors[i-1]+s->sectorcounts[i-1];
  140:                     }
  141:                     chunk_count--;
  142:                     i--;
  143:                     if(lseek(s->fd,36,SEEK_CUR)<0)
  144:                         goto dmg_close;
  145:                     continue;
  146:                 }
  147:                 read_uint32(s->fd);
  148:                 s->sectors[i] = last_out_offset+read_off(s->fd);
  149:                 s->sectorcounts[i] = read_off(s->fd);
  150:                 s->offsets[i] = last_in_offset+read_off(s->fd);
  151:                 s->lengths[i] = read_off(s->fd);
  152:                 if(s->lengths[i]>max_compressed_size)
  153:                     max_compressed_size = s->lengths[i];
  154:                 if(s->sectorcounts[i]>max_sectors_per_chunk)
  155:                     max_sectors_per_chunk = s->sectorcounts[i];
  156:             }
  157:             s->n_chunks+=chunk_count;
  158:         }
  159:     }
  160: 
  161:     /* initialize zlib engine */
  162:     if(!(s->compressed_chunk = malloc(max_compressed_size+1)))
  163:         goto dmg_close;
  164:     if(!(s->uncompressed_chunk = malloc(512*max_sectors_per_chunk)))
  165:         goto dmg_close;
  166:     if(inflateInit(&s->zstream) != Z_OK)
  167:         goto dmg_close;
  168: 
  169:     s->current_chunk = s->n_chunks;
  170: 
  171:     return 0;
  172: }
  173: 
  174: static inline int is_sector_in_chunk(BDRVDMGState* s,
  175:                 uint32_t chunk_num,int sector_num)
  176: {
  177:     if(chunk_num>=s->n_chunks || s->sectors[chunk_num]>sector_num ||
  178:             s->sectors[chunk_num]+s->sectorcounts[chunk_num]<=sector_num)
  179:         return 0;
  180:     else
  181:         return -1;
  182: }
  183: 
  184: static inline uint32_t search_chunk(BDRVDMGState* s,int sector_num)
  185: {
  186:     /* binary search */
  187:     uint32_t chunk1=0,chunk2=s->n_chunks,chunk3;
  188:     while(chunk1!=chunk2) {
  189:         chunk3 = (chunk1+chunk2)/2;
  190:         if(s->sectors[chunk3]>sector_num)
  191:             chunk2 = chunk3;
  192:         else if(s->sectors[chunk3]+s->sectorcounts[chunk3]>sector_num)
  193:             return chunk3;
  194:         else
  195:             chunk1 = chunk3;
  196:     }
  197:     return s->n_chunks; /* error */
  198: }
  199: 
  200: static inline int dmg_read_chunk(BDRVDMGState *s,int sector_num)
  201: {
  202:     if(!is_sector_in_chunk(s,s->current_chunk,sector_num)) {
  203:         int ret;
  204:         uint32_t chunk = search_chunk(s,sector_num);
  205: 
  206:         if(chunk>=s->n_chunks)
  207:             return -1;
  208: 
  209:         s->current_chunk = s->n_chunks;
  210:         switch(s->types[chunk]) {
  211:         case 0x80000005: { /* zlib compressed */
  212:             int i;
  213: 
  214:             ret = lseek(s->fd, s->offsets[chunk], SEEK_SET);
  215:             if(ret<0)
  216:                 return -1;
  217: 
  218:             /* we need to buffer, because only the chunk as whole can be
  219:              * inflated. */
  220:             i=0;
  221:             do {
  222:                 ret = read(s->fd, s->compressed_chunk+i, s->lengths[chunk]-i);
  223:                 if(ret<0 && errno==EINTR)
  224:                     ret=0;
  225:                 i+=ret;
  226:             } while(ret>=0 && ret+i<s->lengths[chunk]);
  227: 
  228:             if (ret != s->lengths[chunk])
  229:                 return -1;
  230: 
  231:             s->zstream.next_in = s->compressed_chunk;
  232:             s->zstream.avail_in = s->lengths[chunk];
  233:             s->zstream.next_out = s->uncompressed_chunk;
  234:             s->zstream.avail_out = 512*s->sectorcounts[chunk];
  235:             ret = inflateReset(&s->zstream);
  236:             if(ret != Z_OK)
  237:                 return -1;
  238:             ret = inflate(&s->zstream, Z_FINISH);
  239:             if(ret != Z_STREAM_END || s->zstream.total_out != 512*s->sectorcounts[chunk])
  240:                 return -1;
  241:             break; }
  242:         case 1: /* copy */
  243:             ret = read(s->fd, s->uncompressed_chunk, s->lengths[chunk]);
  244:             if (ret != s->lengths[chunk])
  245:                 return -1;
  246:             break;
  247:         case 2: /* zero */
  248:             memset(s->uncompressed_chunk, 0, 512*s->sectorcounts[chunk]);
  249:             break;
  250:         }
  251:         s->current_chunk = chunk;
  252:     }
  253:     return 0;
  254: }
  255: 
  256: static int dmg_read(BlockDriverState *bs, int64_t sector_num,
  257:                     uint8_t *buf, int nb_sectors)
  258: {
  259:     BDRVDMGState *s = bs->opaque;
  260:     int i;
  261: 
  262:     for(i=0;i<nb_sectors;i++) {
  263:         uint32_t sector_offset_in_chunk;
  264:         if(dmg_read_chunk(s, sector_num+i) != 0)
  265:             return -1;
  266:         sector_offset_in_chunk = sector_num+i-s->sectors[s->current_chunk];
  267:         memcpy(buf+i*512,s->uncompressed_chunk+sector_offset_in_chunk*512,512);
  268:     }
  269:     return 0;
  270: }
  271: 
  272: static void dmg_close(BlockDriverState *bs)
  273: {
  274:     BDRVDMGState *s = bs->opaque;
  275:     close(s->fd);
  276:     if(s->n_chunks>0) {
  277:         free(s->types);
  278:         free(s->offsets);
  279:         free(s->lengths);
  280:         free(s->sectors);
  281:         free(s->sectorcounts);
  282:     }
  283:     free(s->compressed_chunk);
  284:     free(s->uncompressed_chunk);
  285:     inflateEnd(&s->zstream);
  286: }
  287: 
  288: BlockDriver bdrv_dmg = {
  289:     "dmg",
  290:     sizeof(BDRVDMGState),
  291:     dmg_probe,
  292:     dmg_open,
  293:     dmg_read,
  294:     NULL,
  295:     dmg_close,
  296: };
  297: 
Syntax (Markdown)