On Sat, Feb 18, 2017, 10:17 Andrei Borzenkov <arvidj...@gmail.com> wrote:
> 1. Do not assume block list and fragment are mutually exclusive. Squash > can pack file tail as fragment (unless -no-fragments is specified); so > check read offset and read either from block list or from fragments as > appropriate. > > 2. Support sparse files with zero blocks. > > 3. Fix fragment read - frag.offset is absolute fragment position, > not offset relative to ino.chunk. > Go ahead. > > Reported and tested by Carlo Caione <ca...@endlessm.com> > > --- > > @Vladimir: we need regression tests for both of these cases. We could real > small > files only by accident - block list was zero, so it appeared to work. > How do you create those files reliably? Feel free to add any files to grub-fs-tester. Feel free to commit without tests, we can add tests later. > > @Carlo, please test. I'm surprised it worked for you even without > fragments as > your file is sparse and grub immediately choked on the first zero block. > > grub-core/fs/squash4.c | 55 > +++++++++++++++++++++++++++++++++----------------- > 1 file changed, 36 insertions(+), 19 deletions(-) > > diff --git a/grub-core/fs/squash4.c b/grub-core/fs/squash4.c > index b97b344..deee71a 100644 > --- a/grub-core/fs/squash4.c > +++ b/grub-core/fs/squash4.c > @@ -823,7 +823,12 @@ direct_read (struct grub_squash_data *data, > curread = data->blksz - boff; > if (curread > len) > curread = len; > - if (!(ino->block_sizes[i] > + if (!ino->block_sizes[i]) > + { > + /* Sparse block */ > + grub_memset (buf, '\0', curread); > + } > + else if (!(ino->block_sizes[i] > & grub_cpu_to_le32_compile_time (SQUASH_BLOCK_UNCOMPRESSED))) > { > char *block; > @@ -873,36 +878,57 @@ direct_read (struct grub_squash_data *data, > > > static grub_ssize_t > -grub_squash_read_data (struct grub_squash_data *data, > - struct grub_squash_cache_inode *ino, > - grub_off_t off, char *buf, grub_size_t len) > +grub_squash_read (grub_file_t file, char *buf, grub_size_t len) > { > + struct grub_squash_data *data = file->data; > + struct grub_squash_cache_inode *ino = &data->ino; > + grub_off_t off = file->offset; > grub_err_t err; > grub_uint64_t a = 0, b; > grub_uint32_t fragment = 0; > int compressed = 0; > struct grub_squash_frag_desc frag; > + grub_off_t blk_len; > + grub_uint64_t mask = grub_le_to_cpu32 (data->sb.block_size) - 1; > + grub_size_t orig_len = len; > > switch (ino->ino.type) > { > case grub_cpu_to_le16_compile_time (SQUASH_TYPE_LONG_REGULAR): > - a = grub_le_to_cpu64 (ino->ino.long_file.chunk); > fragment = grub_le_to_cpu32 (ino->ino.long_file.fragment); > break; > case grub_cpu_to_le16_compile_time (SQUASH_TYPE_REGULAR): > - a = grub_le_to_cpu32 (ino->ino.file.chunk); > fragment = grub_le_to_cpu32 (ino->ino.file.fragment); > break; > } > > - if (fragment == 0xffffffff) > - return direct_read (data, ino, off, buf, len); > + /* Squash may pack file tail as fragment. So read initial part directly > and > + get tail from fragments */ > + blk_len = fragment == 0xffffffff ? file->size : file->size & ~mask; > + if (off < blk_len) > + { > + grub_size_t read_len = blk_len - off; > + grub_ssize_t res; > + > + if (read_len > len) > + read_len = len; > + res = direct_read (data, ino, off, buf, read_len); > + if ((grub_size_t) res != read_len) > + return -1; /* FIXME: is short read possible here? */ > + len -= read_len; > + if (!len) > + return read_len; > + buf += read_len; > + off = 0; > + } > + else > + off -= blk_len; > > err = read_chunk (data, &frag, sizeof (frag), > data->fragments, sizeof (frag) * fragment); > if (err) > return -1; > - a += grub_le_to_cpu64 (frag.offset); > + a = grub_le_to_cpu64 (frag.offset); > compressed = !(frag.size & grub_cpu_to_le32_compile_time > (SQUASH_BLOCK_UNCOMPRESSED)); > if (ino->ino.type == grub_cpu_to_le16_compile_time > (SQUASH_TYPE_LONG_REGULAR)) > b = grub_le_to_cpu32 (ino->ino.long_file.offset) + off; > @@ -943,16 +969,7 @@ grub_squash_read_data (struct grub_squash_data *data, > if (err) > return -1; > } > - return len; > -} > - > -static grub_ssize_t > -grub_squash_read (grub_file_t file, char *buf, grub_size_t len) > -{ > - struct grub_squash_data *data = file->data; > - > - return grub_squash_read_data (data, &data->ino, > - file->offset, buf, len); > + return orig_len; > } > > static grub_err_t > -- > tg: (2fb8cd2..) u/squash-tail-fragment (depends on: master) > > _______________________________________________ > Bug-grub mailing list > Bug-grub@gnu.org > https://lists.gnu.org/mailman/listinfo/bug-grub >
_______________________________________________ Bug-grub mailing list Bug-grub@gnu.org https://lists.gnu.org/mailman/listinfo/bug-grub