LCOV - code coverage report
Current view: top level - import - qcow2-util.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 0 159 0.0 %
Date: 2019-08-22 15:41:25 Functions: 0 7 0.0 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: LGPL-2.1+ */
       2             : 
       3             : #include <zlib.h>
       4             : 
       5             : #include "alloc-util.h"
       6             : #include "btrfs-util.h"
       7             : #include "qcow2-util.h"
       8             : #include "sparse-endian.h"
       9             : #include "util.h"
      10             : 
      11             : #define QCOW2_MAGIC 0x514649fb
      12             : 
      13             : #define QCOW2_COPIED (1ULL << 63)
      14             : #define QCOW2_COMPRESSED (1ULL << 62)
      15             : #define QCOW2_ZERO (1ULL << 0)
      16             : 
      17             : typedef struct _packed_ Header {
      18             :       be32_t magic;
      19             :       be32_t version;
      20             : 
      21             :       be64_t backing_file_offset;
      22             :       be32_t backing_file_size;
      23             : 
      24             :       be32_t cluster_bits;
      25             :       be64_t size;
      26             :       be32_t crypt_method;
      27             : 
      28             :       be32_t l1_size;
      29             :       be64_t l1_table_offset;
      30             : 
      31             :       be64_t refcount_table_offset;
      32             :       be32_t refcount_table_clusters;
      33             : 
      34             :       be32_t nb_snapshots;
      35             :       be64_t snapshots_offset;
      36             : 
      37             :       /* The remainder is only present on QCOW3 */
      38             :       be64_t incompatible_features;
      39             :       be64_t compatible_features;
      40             :       be64_t autoclear_features;
      41             : 
      42             :       be32_t refcount_order;
      43             :       be32_t header_length;
      44             : } Header;
      45             : 
      46             : #define HEADER_MAGIC(header) be32toh((header)->magic)
      47             : #define HEADER_VERSION(header) be32toh((header)->version)
      48             : #define HEADER_CLUSTER_BITS(header) be32toh((header)->cluster_bits)
      49             : #define HEADER_CLUSTER_SIZE(header) (1ULL << HEADER_CLUSTER_BITS(header))
      50             : #define HEADER_L2_BITS(header) (HEADER_CLUSTER_BITS(header) - 3)
      51             : #define HEADER_SIZE(header) be64toh((header)->size)
      52             : #define HEADER_CRYPT_METHOD(header) be32toh((header)->crypt_method)
      53             : #define HEADER_L1_SIZE(header) be32toh((header)->l1_size)
      54             : #define HEADER_L2_SIZE(header) (HEADER_CLUSTER_SIZE(header)/sizeof(uint64_t))
      55             : #define HEADER_L1_TABLE_OFFSET(header) be64toh((header)->l1_table_offset)
      56             : 
      57           0 : static uint32_t HEADER_HEADER_LENGTH(const Header *h) {
      58           0 :         if (HEADER_VERSION(h) < 3)
      59           0 :                 return offsetof(Header, incompatible_features);
      60             : 
      61           0 :         return be32toh(h->header_length);
      62             : }
      63             : 
      64           0 : static int copy_cluster(
      65             :                 int sfd, uint64_t soffset,
      66             :                 int dfd, uint64_t doffset,
      67             :                 uint64_t cluster_size,
      68             :                 void *buffer) {
      69             : 
      70             :         ssize_t l;
      71             :         int r;
      72             : 
      73           0 :         r = btrfs_clone_range(sfd, soffset, dfd, doffset, cluster_size);
      74           0 :         if (r >= 0)
      75           0 :                 return r;
      76             : 
      77           0 :         l = pread(sfd, buffer, cluster_size, soffset);
      78           0 :         if (l < 0)
      79           0 :                 return -errno;
      80           0 :         if ((uint64_t) l != cluster_size)
      81           0 :                 return -EIO;
      82             : 
      83           0 :         l = pwrite(dfd, buffer, cluster_size, doffset);
      84           0 :         if (l < 0)
      85           0 :                 return -errno;
      86           0 :         if ((uint64_t) l != cluster_size)
      87           0 :                 return -EIO;
      88             : 
      89           0 :         return 0;
      90             : }
      91             : 
      92           0 : static int decompress_cluster(
      93             :                 int sfd, uint64_t soffset,
      94             :                 int dfd, uint64_t doffset,
      95             :                 uint64_t compressed_size,
      96             :                 uint64_t cluster_size,
      97             :                 void *buffer1,
      98             :                 void *buffer2) {
      99             : 
     100           0 :         _cleanup_free_ void *large_buffer = NULL;
     101           0 :         z_stream s = {};
     102             :         uint64_t sz;
     103             :         ssize_t l;
     104             :         int r;
     105             : 
     106           0 :         if (compressed_size > cluster_size) {
     107             :                 /* The usual cluster buffer doesn't suffice, let's
     108             :                  * allocate a larger one, temporarily */
     109             : 
     110           0 :                 large_buffer = malloc(compressed_size);
     111           0 :                 if (!large_buffer)
     112           0 :                         return -ENOMEM;
     113             : 
     114           0 :                 buffer1 = large_buffer;
     115             :         }
     116             : 
     117           0 :         l = pread(sfd, buffer1, compressed_size, soffset);
     118           0 :         if (l < 0)
     119           0 :                 return -errno;
     120           0 :         if ((uint64_t) l != compressed_size)
     121           0 :                 return -EIO;
     122             : 
     123           0 :         s.next_in = buffer1;
     124           0 :         s.avail_in = compressed_size;
     125           0 :         s.next_out = buffer2;
     126           0 :         s.avail_out = cluster_size;
     127             : 
     128           0 :         r = inflateInit2(&s, -12);
     129           0 :         if (r != Z_OK)
     130           0 :                 return -EIO;
     131             : 
     132           0 :         r = inflate(&s, Z_FINISH);
     133           0 :         sz = (uint8_t*) s.next_out - (uint8_t*) buffer2;
     134           0 :         inflateEnd(&s);
     135           0 :         if (r != Z_STREAM_END || sz != cluster_size)
     136           0 :                 return -EIO;
     137             : 
     138           0 :         l = pwrite(dfd, buffer2, cluster_size, doffset);
     139           0 :         if (l < 0)
     140           0 :                 return -errno;
     141           0 :         if ((uint64_t) l != cluster_size)
     142           0 :                 return -EIO;
     143             : 
     144           0 :         return 0;
     145             : }
     146             : 
     147           0 : static int normalize_offset(
     148             :                 const Header *header,
     149             :                 uint64_t p,
     150             :                 uint64_t *ret,
     151             :                 bool *compressed,
     152             :                 uint64_t *compressed_size) {
     153             : 
     154             :         uint64_t q;
     155             : 
     156           0 :         q = be64toh(p);
     157             : 
     158           0 :         if (q & QCOW2_COMPRESSED) {
     159             :                 uint64_t sz, csize_shift, csize_mask;
     160             : 
     161           0 :                 if (!compressed)
     162           0 :                         return -EOPNOTSUPP;
     163             : 
     164           0 :                 csize_shift = 64 - 2 - (HEADER_CLUSTER_BITS(header) - 8);
     165           0 :                 csize_mask = (1ULL << (HEADER_CLUSTER_BITS(header) - 8)) - 1;
     166           0 :                 sz = (((q >> csize_shift) & csize_mask) + 1) * 512 - (q & 511);
     167           0 :                 q &= ((1ULL << csize_shift) - 1);
     168             : 
     169           0 :                 if (compressed_size)
     170           0 :                         *compressed_size = sz;
     171             : 
     172           0 :                 *compressed = true;
     173             : 
     174             :         } else {
     175           0 :                 if (compressed)  {
     176           0 :                         *compressed = false;
     177           0 :                         *compressed_size = 0;
     178             :                 }
     179             : 
     180           0 :                 if (q & QCOW2_ZERO) {
     181             :                         /* We make no distinction between zero blocks and holes */
     182           0 :                         *ret = 0;
     183           0 :                         return 0;
     184             :                 }
     185             : 
     186           0 :                 q &= ~QCOW2_COPIED;
     187             :         }
     188             : 
     189           0 :         *ret = q;
     190           0 :         return q > 0;  /* returns positive if not a hole */
     191             : }
     192             : 
     193           0 : static int verify_header(const Header *header) {
     194           0 :         assert(header);
     195             : 
     196           0 :         if (HEADER_MAGIC(header) != QCOW2_MAGIC)
     197           0 :                 return -EBADMSG;
     198             : 
     199           0 :         if (!IN_SET(HEADER_VERSION(header), 2, 3))
     200           0 :                 return -EOPNOTSUPP;
     201             : 
     202           0 :         if (HEADER_CRYPT_METHOD(header) != 0)
     203           0 :                 return -EOPNOTSUPP;
     204             : 
     205           0 :         if (HEADER_CLUSTER_BITS(header) < 9) /* 512K */
     206           0 :                 return -EBADMSG;
     207             : 
     208           0 :         if (HEADER_CLUSTER_BITS(header) > 21) /* 2MB */
     209           0 :                 return -EBADMSG;
     210             : 
     211           0 :         if (HEADER_SIZE(header) % HEADER_CLUSTER_SIZE(header) != 0)
     212           0 :                 return -EBADMSG;
     213             : 
     214           0 :         if (HEADER_L1_SIZE(header) > 32*1024*1024) /* 32MB */
     215           0 :                 return -EBADMSG;
     216             : 
     217           0 :         if (HEADER_VERSION(header) == 3) {
     218             : 
     219           0 :                 if (header->incompatible_features != 0)
     220           0 :                         return -EOPNOTSUPP;
     221             : 
     222           0 :                 if (HEADER_HEADER_LENGTH(header) < sizeof(Header))
     223           0 :                         return -EBADMSG;
     224             :         }
     225             : 
     226           0 :         return 0;
     227             : }
     228             : 
     229           0 : int qcow2_convert(int qcow2_fd, int raw_fd) {
     230           0 :         _cleanup_free_ void *buffer1 = NULL, *buffer2 = NULL;
     231           0 :         _cleanup_free_ be64_t *l1_table = NULL, *l2_table = NULL;
     232             :         uint64_t sz, i;
     233             :         Header header;
     234             :         ssize_t l;
     235             :         int r;
     236             : 
     237           0 :         l = pread(qcow2_fd, &header, sizeof(header), 0);
     238           0 :         if (l < 0)
     239           0 :                 return -errno;
     240           0 :         if (l != sizeof(header))
     241           0 :                 return -EIO;
     242             : 
     243           0 :         r = verify_header(&header);
     244           0 :         if (r < 0)
     245           0 :                 return r;
     246             : 
     247           0 :         l1_table = new(be64_t, HEADER_L1_SIZE(&header));
     248           0 :         if (!l1_table)
     249           0 :                 return -ENOMEM;
     250             : 
     251           0 :         l2_table = malloc(HEADER_CLUSTER_SIZE(&header));
     252           0 :         if (!l2_table)
     253           0 :                 return -ENOMEM;
     254             : 
     255           0 :         buffer1 = malloc(HEADER_CLUSTER_SIZE(&header));
     256           0 :         if (!buffer1)
     257           0 :                 return -ENOMEM;
     258             : 
     259           0 :         buffer2 = malloc(HEADER_CLUSTER_SIZE(&header));
     260           0 :         if (!buffer2)
     261           0 :                 return -ENOMEM;
     262             : 
     263             :         /* Empty the file if it exists, we rely on zero bits */
     264           0 :         if (ftruncate(raw_fd, 0) < 0)
     265           0 :                 return -errno;
     266             : 
     267           0 :         if (ftruncate(raw_fd, HEADER_SIZE(&header)) < 0)
     268           0 :                 return -errno;
     269             : 
     270           0 :         sz = sizeof(uint64_t) * HEADER_L1_SIZE(&header);
     271           0 :         l = pread(qcow2_fd, l1_table, sz, HEADER_L1_TABLE_OFFSET(&header));
     272           0 :         if (l < 0)
     273           0 :                 return -errno;
     274           0 :         if ((uint64_t) l != sz)
     275           0 :                 return -EIO;
     276             : 
     277           0 :         for (i = 0; i < HEADER_L1_SIZE(&header); i ++) {
     278             :                 uint64_t l2_begin, j;
     279             : 
     280           0 :                 r = normalize_offset(&header, l1_table[i], &l2_begin, NULL, NULL);
     281           0 :                 if (r < 0)
     282           0 :                         return r;
     283           0 :                 if (r == 0)
     284           0 :                         continue;
     285             : 
     286           0 :                 l = pread(qcow2_fd, l2_table, HEADER_CLUSTER_SIZE(&header), l2_begin);
     287           0 :                 if (l < 0)
     288           0 :                         return -errno;
     289           0 :                 if ((uint64_t) l != HEADER_CLUSTER_SIZE(&header))
     290           0 :                         return -EIO;
     291             : 
     292           0 :                 for (j = 0; j < HEADER_L2_SIZE(&header); j++) {
     293             :                         uint64_t data_begin, p, compressed_size;
     294             :                         bool compressed;
     295             : 
     296           0 :                         p = ((i << HEADER_L2_BITS(&header)) + j) << HEADER_CLUSTER_BITS(&header);
     297             : 
     298           0 :                         r = normalize_offset(&header, l2_table[j], &data_begin, &compressed, &compressed_size);
     299           0 :                         if (r < 0)
     300           0 :                                 return r;
     301           0 :                         if (r == 0)
     302           0 :                                 continue;
     303             : 
     304           0 :                         if (compressed)
     305           0 :                                 r = decompress_cluster(
     306             :                                                 qcow2_fd, data_begin,
     307             :                                                 raw_fd, p,
     308           0 :                                                 compressed_size, HEADER_CLUSTER_SIZE(&header),
     309             :                                                 buffer1, buffer2);
     310             :                         else
     311           0 :                                 r = copy_cluster(
     312             :                                                 qcow2_fd, data_begin,
     313             :                                                 raw_fd, p,
     314           0 :                                                 HEADER_CLUSTER_SIZE(&header), buffer1);
     315           0 :                         if (r < 0)
     316           0 :                                 return r;
     317             :                 }
     318             :         }
     319             : 
     320           0 :         return 0;
     321             : }
     322             : 
     323           0 : int qcow2_detect(int fd) {
     324             :         be32_t id;
     325             :         ssize_t l;
     326             : 
     327           0 :         l = pread(fd, &id, sizeof(id), 0);
     328           0 :         if (l < 0)
     329           0 :                 return -errno;
     330           0 :         if (l != sizeof(id))
     331           0 :                 return -EIO;
     332             : 
     333           0 :         return htobe32(QCOW2_MAGIC) == id;
     334             : }

Generated by: LCOV version 1.14