zlib_wrapper.c 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * Squashfs - a compressed read only filesystem for Linux
  4. *
  5. * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
  6. * Phillip Lougher <phillip@squashfs.org.uk>
  7. *
  8. * zlib_wrapper.c
  9. */
  10. #include <linux/mutex.h>
  11. #include <linux/bio.h>
  12. #include <linux/slab.h>
  13. #include <linux/zlib.h>
  14. #include <linux/vmalloc.h>
  15. #include "squashfs_fs.h"
  16. #include "squashfs_fs_sb.h"
  17. #include "squashfs.h"
  18. #include "decompressor.h"
  19. #include "page_actor.h"
  20. static void *zlib_init(struct squashfs_sb_info *dummy, void *buff)
  21. {
  22. z_stream *stream = kmalloc(sizeof(z_stream), GFP_KERNEL);
  23. if (stream == NULL)
  24. goto failed;
  25. stream->workspace = vmalloc(zlib_inflate_workspacesize());
  26. if (stream->workspace == NULL)
  27. goto failed;
  28. return stream;
  29. failed:
  30. ERROR("Failed to allocate zlib workspace\n");
  31. kfree(stream);
  32. return ERR_PTR(-ENOMEM);
  33. }
  34. static void zlib_free(void *strm)
  35. {
  36. z_stream *stream = strm;
  37. if (stream)
  38. vfree(stream->workspace);
  39. kfree(stream);
  40. }
  41. static int zlib_uncompress(struct squashfs_sb_info *msblk, void *strm,
  42. struct bio *bio, int offset, int length,
  43. struct squashfs_page_actor *output)
  44. {
  45. struct bvec_iter_all iter_all = {};
  46. struct bio_vec *bvec = bvec_init_iter_all(&iter_all);
  47. int zlib_init = 0, error = 0;
  48. z_stream *stream = strm;
  49. stream->avail_out = PAGE_SIZE;
  50. stream->next_out = squashfs_first_page(output);
  51. stream->avail_in = 0;
  52. for (;;) {
  53. int zlib_err;
  54. if (stream->avail_in == 0) {
  55. const void *data;
  56. int avail;
  57. if (!bio_next_segment(bio, &iter_all)) {
  58. /* Z_STREAM_END must be reached. */
  59. error = -EIO;
  60. break;
  61. }
  62. avail = min(length, ((int)bvec->bv_len) - offset);
  63. data = page_address(bvec->bv_page) + bvec->bv_offset;
  64. length -= avail;
  65. stream->next_in = data + offset;
  66. stream->avail_in = avail;
  67. offset = 0;
  68. }
  69. if (stream->avail_out == 0) {
  70. stream->next_out = squashfs_next_page(output);
  71. if (stream->next_out != NULL)
  72. stream->avail_out = PAGE_SIZE;
  73. }
  74. if (!zlib_init) {
  75. zlib_err = zlib_inflateInit(stream);
  76. if (zlib_err != Z_OK) {
  77. error = -EIO;
  78. break;
  79. }
  80. zlib_init = 1;
  81. }
  82. zlib_err = zlib_inflate(stream, Z_SYNC_FLUSH);
  83. if (zlib_err == Z_STREAM_END)
  84. break;
  85. if (zlib_err != Z_OK) {
  86. error = -EIO;
  87. break;
  88. }
  89. }
  90. squashfs_finish_page(output);
  91. if (!error)
  92. if (zlib_inflateEnd(stream) != Z_OK)
  93. error = -EIO;
  94. return error ? error : stream->total_out;
  95. }
  96. const struct squashfs_decompressor squashfs_zlib_comp_ops = {
  97. .init = zlib_init,
  98. .free = zlib_free,
  99. .decompress = zlib_uncompress,
  100. .id = ZLIB_COMPRESSION,
  101. .name = "zlib",
  102. .supported = 1
  103. };