zlib_wrapper.c 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  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 <[email protected]>
  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. if (IS_ERR(stream->next_out)) {
  53. error = PTR_ERR(stream->next_out);
  54. goto finish;
  55. }
  56. for (;;) {
  57. int zlib_err;
  58. if (stream->avail_in == 0) {
  59. const void *data;
  60. int avail;
  61. if (!bio_next_segment(bio, &iter_all)) {
  62. /* Z_STREAM_END must be reached. */
  63. error = -EIO;
  64. break;
  65. }
  66. avail = min(length, ((int)bvec->bv_len) - offset);
  67. data = bvec_virt(bvec);
  68. length -= avail;
  69. stream->next_in = data + offset;
  70. stream->avail_in = avail;
  71. offset = 0;
  72. }
  73. if (stream->avail_out == 0) {
  74. stream->next_out = squashfs_next_page(output);
  75. if (IS_ERR(stream->next_out)) {
  76. error = PTR_ERR(stream->next_out);
  77. break;
  78. } else if (stream->next_out != NULL)
  79. stream->avail_out = PAGE_SIZE;
  80. }
  81. if (!zlib_init) {
  82. zlib_err = zlib_inflateInit(stream);
  83. if (zlib_err != Z_OK) {
  84. error = -EIO;
  85. break;
  86. }
  87. zlib_init = 1;
  88. }
  89. zlib_err = zlib_inflate(stream, Z_SYNC_FLUSH);
  90. if (zlib_err == Z_STREAM_END)
  91. break;
  92. if (zlib_err != Z_OK) {
  93. error = -EIO;
  94. break;
  95. }
  96. }
  97. finish:
  98. squashfs_finish_page(output);
  99. if (!error)
  100. if (zlib_inflateEnd(stream) != Z_OK)
  101. error = -EIO;
  102. return error ? error : stream->total_out;
  103. }
  104. const struct squashfs_decompressor squashfs_zlib_comp_ops = {
  105. .init = zlib_init,
  106. .free = zlib_free,
  107. .decompress = zlib_uncompress,
  108. .id = ZLIB_COMPRESSION,
  109. .name = "zlib",
  110. .alloc_buffer = 1,
  111. .supported = 1
  112. };