}
while (pos < inode->i_size) {
+ unsigned int alloc_rawsize;
+
map.m_la = pos;
if (compressed)
ret = z_erofs_map_blocks_iter(inode, &map,
if (!(map.m_flags & EROFS_MAP_MAPPED) || !fsckcfg.check_decomp)
continue;
- if (map.m_plen > raw_size) {
- raw_size = map.m_plen;
- raw = realloc(raw, raw_size);
- BUG_ON(!raw);
+ if (map.m_plen > Z_EROFS_PCLUSTER_MAX_SIZE) {
+ if (compressed) {
+ erofs_err("invalid pcluster size %" PRIu64 " @ offset %" PRIu64 " of nid %" PRIu64,
+ map.m_plen, map.m_la,
+ inode->nid | 0ULL);
+ ret = -EFSCORRUPTED;
+ goto out;
+ }
+ alloc_rawsize = Z_EROFS_PCLUSTER_MAX_SIZE;
+ } else {
+ alloc_rawsize = map.m_plen;
+ }
+
+ if (alloc_rawsize > raw_size) {
+ char *newraw = realloc(raw, alloc_rawsize);
+
+ if (!newraw) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ raw = newraw;
+ raw_size = alloc_rawsize;
}
if (compressed) {
}
ret = z_erofs_read_one_data(inode, &map, raw, buffer,
0, map.m_llen, false);
+ if (ret)
+ goto out;
+
+ if (outfd >= 0 && write(outfd, buffer, map.m_llen) < 0)
+ goto fail_eio;
} else {
- ret = erofs_read_one_data(&map, raw, 0, map.m_plen);
- }
- if (ret)
- goto out;
+ u64 p = 0;
- if (outfd >= 0 && write(outfd, compressed ? buffer : raw,
- map.m_llen) < 0) {
- erofs_err("I/O error occurred when verifying data chunk @ nid %llu",
- inode->nid | 0ULL);
- ret = -EIO;
- goto out;
+ do {
+ u64 count = min_t(u64, alloc_rawsize,
+ map.m_llen);
+
+ ret = erofs_read_one_data(&map, raw, p, count);
+ if (ret)
+ goto out;
+
+ if (outfd >= 0 && write(outfd, raw, count) < 0)
+ goto fail_eio;
+ map.m_llen -= count;
+ p += count;
+ } while (map.m_llen);
}
}
if (buffer)
free(buffer);
return ret < 0 ? ret : 0;
+
+fail_eio:
+ erofs_err("I/O error occurred when verifying data chunk @ nid %llu",
+ inode->nid | 0ULL);
+ ret = -EIO;
+ goto out;
}
static inline int erofs_extract_dir(struct erofs_inode *inode)