int read_block(int fd, long long start, long long *next, int expected, void *block) { unsigned short c_byte; int res, compressed; int outlen = expected ? expected : SQUASHFS_METADATA_SIZE; /* Read block size */ res = read_fs_bytes(fd, start, 2, &c_byte); if(res == 0) return 0; SQUASHFS_INSWAP_SHORTS(&c_byte, 1); compressed = SQUASHFS_COMPRESSED(c_byte); c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte); /* * The block size should not be larger than * the uncompressed size (or max uncompressed size if * expected is 0) */ if (c_byte > outlen) return 0; if(compressed) { char buffer[c_byte]; int error; res = read_fs_bytes(fd, start + 2, c_byte, buffer); if(res == 0) return 0; res = compressor_uncompress(comp, block, buffer, c_byte, outlen, &error); if(res == -1) { // CJH: Decompression errors are displayed elsewhere //ERROR("%s uncompress failed with error code %d\n", // comp->name, error); return 0; } } else { res = read_fs_bytes(fd, start + 2, c_byte, block); if(res == 0) return 0; res = c_byte; } if(next) *next = start + 2 + c_byte; /* * if expected, then check the (uncompressed) return data * is of the expected size */ if(expected && expected != res) return 0; else return res; }
static struct file_buffer *get_fragment(struct fragment *fragment, char *data_buffer, int fd) { struct squashfs_fragment_entry *disk_fragment; struct file_buffer *buffer, *compressed_buffer; long long start_block; int res, size, index = fragment->index; char locked; /* * Lookup fragment block in cache. * If the fragment block doesn't exist, then get the compressed version * from the writer cache or off disk, and decompress it. * * This routine has two things which complicate the code: * * 1. Multiple threads can simultaneously lookup/create the * same buffer. This means a buffer needs to be "locked" * when it is being filled in, to prevent other threads from * using it when it is not ready. This is because we now do * fragment duplicate checking in parallel. * 2. We have two caches which need to be checked for the * presence of fragment blocks: the normal fragment cache * and a "reserve" cache. The reserve cache is used to * prevent an unnecessary pipeline stall when the fragment cache * is full of fragments waiting to be compressed. */ pthread_cleanup_push((void *)pthread_mutex_unlock, &dup_mutex); pthread_mutex_lock(&dup_mutex); again: buffer = cache_lookup_nowait(fragment_buffer, index, &locked); if (buffer) { pthread_mutex_unlock(&dup_mutex); if (locked) /* got a buffer being filled in. Wait for it */ cache_wait_unlock(buffer); goto finished; } /* not in fragment cache, is it in the reserve cache? */ buffer = cache_lookup_nowait(reserve_cache, index, &locked); if (buffer) { pthread_mutex_unlock(&dup_mutex); if (locked) /* got a buffer being filled in. Wait for it */ cache_wait_unlock(buffer); goto finished; } /* in neither cache, try to get it from the fragment cache */ buffer = cache_get_nowait(fragment_buffer, index); if (!buffer) { /* * no room, get it from the reserve cache, this is * dimensioned so it will always have space (no more than * processors + 1 can have an outstanding reserve buffer) */ buffer = cache_get_nowait(reserve_cache, index); if (!buffer) { /* failsafe */ ERROR("no space in reserve cache\n"); goto again; } } pthread_mutex_unlock(&dup_mutex); compressed_buffer = cache_lookup(fwriter_buffer, index); pthread_cleanup_push((void *)pthread_mutex_unlock, &fragment_mutex); pthread_mutex_lock(&fragment_mutex); disk_fragment = &fragment_table[index]; size = SQUASHFS_COMPRESSED_SIZE_BLOCK(disk_fragment->size); start_block = disk_fragment->start_block; pthread_cleanup_pop(1); if (SQUASHFS_COMPRESSED_BLOCK(disk_fragment->size)) { int error; char *data; if (compressed_buffer) data = compressed_buffer->data; else { res = read_filesystem(fd, start_block, size, data_buffer); if (res == 0) { ERROR("Failed to read fragment from output" " filesystem\n"); BAD_ERROR("Output filesystem corrupted?\n"); } data = data_buffer; } res = compressor_uncompress(comp, buffer->data, data, size, block_size, &error); if (res == -1) BAD_ERROR("%s uncompress failed with error code %d\n", comp->name, error); } else if (compressed_buffer) memcpy(buffer->data, compressed_buffer->data, size); else { res = read_filesystem(fd, start_block, size, buffer->data); if (res == 0) { ERROR("Failed to read fragment from output " "filesystem\n"); BAD_ERROR("Output filesystem corrupted?\n"); } } cache_unlock(buffer); cache_block_put(compressed_buffer); finished: pthread_cleanup_pop(0); return buffer; }