#include <sys/stat.h>
#include <unistd.h>
+#include "util/blob.h"
#include "util/crc32.h"
#include "util/debug.h"
#include "util/disk_cache.h"
p_atomic_add(cache->size, - (uint64_t)sb.st_blocks * 512);
}
-void *
-disk_cache_load_item(struct disk_cache *cache, char *filename, size_t *size)
+static void *
+parse_and_validate_cache_item(struct disk_cache *cache, void *cache_item,
+ size_t cache_item_size, size_t *size)
{
- int fd = -1, ret;
- struct stat sb;
- uint8_t *data = NULL;
uint8_t *uncompressed_data = NULL;
- uint8_t *file_header = NULL;
-
- fd = open(filename, O_RDONLY | O_CLOEXEC);
- if (fd == -1)
- goto fail;
-
- if (fstat(fd, &sb) == -1)
- goto fail;
-
- data = malloc(sb.st_size);
- if (data == NULL)
- goto fail;
-
- size_t ck_size = cache->driver_keys_blob_size;
- file_header = malloc(ck_size);
- if (!file_header)
- goto fail;
- if (sb.st_size < ck_size)
- goto fail;
+ struct blob_reader ci_blob_reader;
+ blob_reader_init(&ci_blob_reader, cache_item, cache_item_size);
- ret = read_all(fd, file_header, ck_size);
- if (ret == -1)
+ size_t header_size = cache->driver_keys_blob_size;
+ const void *keys_blob = blob_read_bytes(&ci_blob_reader, header_size);
+ if (ci_blob_reader.overrun)
goto fail;
/* Check for extremely unlikely hash collisions */
- if (memcmp(cache->driver_keys_blob, file_header, ck_size) != 0) {
+ if (memcmp(cache->driver_keys_blob, keys_blob, header_size) != 0) {
assert(!"Mesa cache keys mismatch!");
goto fail;
}
- size_t cache_item_md_size = sizeof(uint32_t);
- uint32_t md_type;
- ret = read_all(fd, &md_type, cache_item_md_size);
- if (ret == -1)
+ uint32_t md_type = blob_read_uint32(&ci_blob_reader);
+ if (ci_blob_reader.overrun)
goto fail;
if (md_type == CACHE_ITEM_TYPE_GLSL) {
- uint32_t num_keys;
- cache_item_md_size += sizeof(uint32_t);
- ret = read_all(fd, &num_keys, sizeof(uint32_t));
- if (ret == -1)
+ uint32_t num_keys = blob_read_uint32(&ci_blob_reader);
+ if (ci_blob_reader.overrun)
goto fail;
/* The cache item metadata is currently just used for distributing
* TODO: pass the metadata back to the caller and do some basic
* validation.
*/
- cache_item_md_size += num_keys * sizeof(cache_key);
- ret = lseek(fd, num_keys * sizeof(cache_key), SEEK_CUR);
- if (ret == -1)
+ const void UNUSED *metadata =
+ blob_read_bytes(&ci_blob_reader, num_keys * sizeof(cache_key));
+ if (ci_blob_reader.overrun)
goto fail;
}
/* Load the CRC that was created when the file was written. */
- struct cache_entry_file_data cf_data;
- size_t cf_data_size = sizeof(cf_data);
- ret = read_all(fd, &cf_data, cf_data_size);
- if (ret == -1)
+ struct cache_entry_file_data *cf_data =
+ (struct cache_entry_file_data *)
+ blob_read_bytes(&ci_blob_reader, sizeof(struct cache_entry_file_data));
+ if (ci_blob_reader.overrun)
goto fail;
- /* Load the actual cache data. */
- size_t cache_data_size =
- sb.st_size - cf_data_size - ck_size - cache_item_md_size;
- ret = read_all(fd, data, cache_data_size);
- if (ret == -1)
- goto fail;
+ size_t cache_data_size = ci_blob_reader.end - ci_blob_reader.current;
+ const uint8_t *data = (uint8_t *) blob_read_bytes(&ci_blob_reader, cache_data_size);
/* Check the data for corruption */
- if (cf_data.crc32 != util_hash_crc32(data, cache_data_size))
+ if (cf_data->crc32 != util_hash_crc32(data, cache_data_size))
goto fail;
/* Uncompress the cache data */
- uncompressed_data = malloc(cf_data.uncompressed_size);
+ uncompressed_data = malloc(cf_data->uncompressed_size);
if (!util_compress_inflate(data, cache_data_size, uncompressed_data,
- cf_data.uncompressed_size))
+ cf_data->uncompressed_size))
+ goto fail;
+
+ if (size)
+ *size = cf_data->uncompressed_size;
+
+ return uncompressed_data;
+
+ fail:
+ if (uncompressed_data)
+ free(uncompressed_data);
+
+ return NULL;
+}
+
+void *
+disk_cache_load_item(struct disk_cache *cache, char *filename, size_t *size)
+{
+ uint8_t *data = NULL;
+
+ int fd = open(filename, O_RDONLY | O_CLOEXEC);
+ if (fd == -1)
+ goto fail;
+
+ struct stat sb;
+ if (fstat(fd, &sb) == -1)
+ goto fail;
+
+ data = malloc(sb.st_size);
+ if (data == NULL)
+ goto fail;
+
+ /* Read entire file into memory */
+ int ret = read_all(fd, data, sb.st_size);
+ if (ret == -1)
+ goto fail;
+
+ uint8_t *uncompressed_data =
+ parse_and_validate_cache_item(cache, data, sb.st_size, size);
+ if (!uncompressed_data)
goto fail;
free(data);
free(filename);
- free(file_header);
close(fd);
- if (size)
- *size = cf_data.uncompressed_size;
-
return uncompressed_data;
fail:
free(data);
if (filename)
free(filename);
- if (uncompressed_data)
- free(uncompressed_data);
- if (file_header)
- free(file_header);
if (fd != -1)
close(fd);