ntfscomp.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. /* ntfscomp.c - compression support for the NTFS filesystem */
  2. /*
  3. * Copyright (C) 2007 Free Software Foundation, Inc.
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include <grub/file.h>
  19. #include <grub/mm.h>
  20. #include <grub/misc.h>
  21. #include <grub/disk.h>
  22. #include <grub/dl.h>
  23. #include <grub/fshelp.h>
  24. #include <grub/ntfs.h>
  25. static grub_err_t
  26. decomp_nextvcn (struct grub_ntfs_comp *cc)
  27. {
  28. if (cc->comp_head >= cc->comp_tail)
  29. return grub_error (GRUB_ERR_BAD_FS, "compression block overflown");
  30. if (grub_disk_read
  31. (cc->disk,
  32. (cc->comp_table[cc->comp_head][1] -
  33. (cc->comp_table[cc->comp_head][0] - cc->cbuf_vcn)) * cc->spc, 0,
  34. cc->spc << BLK_SHR, cc->cbuf))
  35. return grub_errno;
  36. cc->cbuf_vcn++;
  37. if ((cc->cbuf_vcn >= cc->comp_table[cc->comp_head][0]))
  38. cc->comp_head++;
  39. cc->cbuf_ofs = 0;
  40. return 0;
  41. }
  42. static grub_err_t
  43. decomp_getch (struct grub_ntfs_comp *cc, unsigned char *res)
  44. {
  45. if (cc->cbuf_ofs >= (cc->spc << BLK_SHR))
  46. {
  47. if (decomp_nextvcn (cc))
  48. return grub_errno;
  49. }
  50. *res = (unsigned char) cc->cbuf[cc->cbuf_ofs++];
  51. return 0;
  52. }
  53. static grub_err_t
  54. decomp_get16 (struct grub_ntfs_comp *cc, grub_uint16_t * res)
  55. {
  56. unsigned char c1 = 0, c2 = 0;
  57. if ((decomp_getch (cc, &c1)) || (decomp_getch (cc, &c2)))
  58. return grub_errno;
  59. *res = ((grub_uint16_t) c2) * 256 + ((grub_uint16_t) c1);
  60. return 0;
  61. }
  62. /* Decompress a block (4096 bytes) */
  63. static grub_err_t
  64. decomp_block (struct grub_ntfs_comp *cc, char *dest)
  65. {
  66. grub_uint16_t flg, cnt;
  67. if (decomp_get16 (cc, &flg))
  68. return grub_errno;
  69. cnt = (flg & 0xFFF) + 1;
  70. if (dest)
  71. {
  72. if (flg & 0x8000)
  73. {
  74. unsigned char tag;
  75. grub_uint32_t bits, copied;
  76. bits = copied = tag = 0;
  77. while (cnt > 0)
  78. {
  79. if (copied > COM_LEN)
  80. return grub_error (GRUB_ERR_BAD_FS,
  81. "compression block too large");
  82. if (!bits)
  83. {
  84. if (decomp_getch (cc, &tag))
  85. return grub_errno;
  86. bits = 8;
  87. cnt--;
  88. if (cnt <= 0)
  89. break;
  90. }
  91. if (tag & 1)
  92. {
  93. grub_uint32_t i, len, delta, code, lmask, dshift;
  94. grub_uint16_t word;
  95. if (decomp_get16 (cc, &word))
  96. return grub_errno;
  97. code = word;
  98. cnt -= 2;
  99. if (!copied)
  100. {
  101. grub_error (GRUB_ERR_BAD_FS, "nontext window empty");
  102. return 0;
  103. }
  104. for (i = copied - 1, lmask = 0xFFF, dshift = 12; i >= 0x10;
  105. i >>= 1)
  106. {
  107. lmask >>= 1;
  108. dshift--;
  109. }
  110. delta = code >> dshift;
  111. len = (code & lmask) + 3;
  112. for (i = 0; i < len; i++)
  113. {
  114. dest[copied] = dest[copied - delta - 1];
  115. copied++;
  116. }
  117. }
  118. else
  119. {
  120. unsigned char ch = 0;
  121. if (decomp_getch (cc, &ch))
  122. return grub_errno;
  123. dest[copied++] = ch;
  124. cnt--;
  125. }
  126. tag >>= 1;
  127. bits--;
  128. }
  129. return 0;
  130. }
  131. else
  132. {
  133. if (cnt != COM_LEN)
  134. return grub_error (GRUB_ERR_BAD_FS,
  135. "invalid compression block size");
  136. }
  137. }
  138. while (cnt > 0)
  139. {
  140. int n;
  141. n = (cc->spc << BLK_SHR) - cc->cbuf_ofs;
  142. if (n > cnt)
  143. n = cnt;
  144. if ((dest) && (n))
  145. {
  146. grub_memcpy (dest, &cc->cbuf[cc->cbuf_ofs], n);
  147. dest += n;
  148. }
  149. cnt -= n;
  150. cc->cbuf_ofs += n;
  151. if ((cnt) && (decomp_nextvcn (cc)))
  152. return grub_errno;
  153. }
  154. return 0;
  155. }
  156. static grub_err_t
  157. read_block (struct grub_ntfs_rlst *ctx, char *buf, int num)
  158. {
  159. int cpb = COM_SEC / ctx->comp.spc;
  160. while (num)
  161. {
  162. int nn;
  163. if ((ctx->target_vcn & 0xF) == 0)
  164. {
  165. if (ctx->comp.comp_head != ctx->comp.comp_tail)
  166. return grub_error (GRUB_ERR_BAD_FS, "invalid compression block");
  167. ctx->comp.comp_head = ctx->comp.comp_tail = 0;
  168. ctx->comp.cbuf_vcn = ctx->target_vcn;
  169. ctx->comp.cbuf_ofs = (ctx->comp.spc << BLK_SHR);
  170. if (ctx->target_vcn >= ctx->next_vcn)
  171. {
  172. if (grub_ntfs_read_run_list (ctx))
  173. return grub_errno;
  174. }
  175. while (ctx->target_vcn + 16 > ctx->next_vcn)
  176. {
  177. if (ctx->flags & RF_BLNK)
  178. break;
  179. ctx->comp.comp_table[ctx->comp.comp_tail][0] = ctx->next_vcn;
  180. ctx->comp.comp_table[ctx->comp.comp_tail][1] =
  181. ctx->curr_lcn + ctx->next_vcn - ctx->curr_vcn;
  182. ctx->comp.comp_tail++;
  183. if (grub_ntfs_read_run_list (ctx))
  184. return grub_errno;
  185. }
  186. }
  187. nn = (16 - (unsigned) (ctx->target_vcn & 0xF)) / cpb;
  188. if (nn > num)
  189. nn = num;
  190. num -= nn;
  191. if (ctx->flags & RF_BLNK)
  192. {
  193. ctx->target_vcn += nn * cpb;
  194. if (ctx->comp.comp_tail == 0)
  195. {
  196. if (buf)
  197. {
  198. grub_memset (buf, 0, nn * COM_LEN);
  199. buf += nn * COM_LEN;
  200. }
  201. }
  202. else
  203. {
  204. while (nn)
  205. {
  206. if (decomp_block (&ctx->comp, buf))
  207. return grub_errno;
  208. if (buf)
  209. buf += COM_LEN;
  210. nn--;
  211. }
  212. }
  213. }
  214. else
  215. {
  216. nn *= cpb;
  217. while ((ctx->comp.comp_head < ctx->comp.comp_tail) && (nn))
  218. {
  219. int tt;
  220. tt =
  221. ctx->comp.comp_table[ctx->comp.comp_head][0] -
  222. ctx->target_vcn;
  223. if (tt > nn)
  224. tt = nn;
  225. ctx->target_vcn += tt;
  226. if (buf)
  227. {
  228. if (grub_disk_read
  229. (ctx->comp.disk,
  230. (ctx->comp.comp_table[ctx->comp.comp_head][1] -
  231. (ctx->comp.comp_table[ctx->comp.comp_head][0] -
  232. ctx->target_vcn)) * ctx->comp.spc, 0,
  233. tt * (ctx->comp.spc << BLK_SHR), buf))
  234. return grub_errno;
  235. buf += tt * (ctx->comp.spc << BLK_SHR);
  236. }
  237. nn -= tt;
  238. if (ctx->target_vcn >=
  239. ctx->comp.comp_table[ctx->comp.comp_head][0])
  240. ctx->comp.comp_head++;
  241. }
  242. if (nn)
  243. {
  244. if (buf)
  245. {
  246. if (grub_disk_read
  247. (ctx->comp.disk,
  248. (ctx->target_vcn - ctx->curr_vcn +
  249. ctx->curr_lcn) * ctx->comp.spc, 0,
  250. nn * (ctx->comp.spc << BLK_SHR), buf))
  251. return grub_errno;
  252. buf += nn * (ctx->comp.spc << BLK_SHR);
  253. }
  254. ctx->target_vcn += nn;
  255. }
  256. }
  257. }
  258. return 0;
  259. }
  260. static grub_err_t
  261. ntfscomp (struct grub_ntfs_attr *at, char *dest, grub_uint32_t ofs,
  262. grub_uint32_t len, struct grub_ntfs_rlst *ctx, grub_uint32_t vcn)
  263. {
  264. grub_err_t ret;
  265. ctx->comp.comp_head = ctx->comp.comp_tail = 0;
  266. ctx->comp.cbuf = grub_malloc ((ctx->comp.spc) << BLK_SHR);
  267. if (!ctx->comp.cbuf)
  268. return 0;
  269. ret = 0;
  270. //ctx->comp.disk->read_hook = read_hook;
  271. if ((vcn > ctx->target_vcn) &&
  272. (read_block
  273. (ctx, NULL, ((vcn - ctx->target_vcn) * ctx->comp.spc) / COM_SEC)))
  274. {
  275. ret = grub_errno;
  276. goto quit;
  277. }
  278. if (ofs % COM_LEN)
  279. {
  280. grub_uint32_t t, n, o;
  281. t = ctx->target_vcn * (ctx->comp.spc << BLK_SHR);
  282. if (read_block (ctx, at->sbuf, 1))
  283. {
  284. ret = grub_errno;
  285. goto quit;
  286. }
  287. at->save_pos = t;
  288. o = ofs % COM_LEN;
  289. n = COM_LEN - o;
  290. if (n > len)
  291. n = len;
  292. grub_memcpy (dest, &at->sbuf[o], n);
  293. if (n == len)
  294. goto quit;
  295. dest += n;
  296. len -= n;
  297. }
  298. if (read_block (ctx, dest, len / COM_LEN))
  299. {
  300. ret = grub_errno;
  301. goto quit;
  302. }
  303. dest += (len / COM_LEN) * COM_LEN;
  304. len = len % COM_LEN;
  305. if (len)
  306. {
  307. grub_uint32_t t;
  308. t = ctx->target_vcn * (ctx->comp.spc << BLK_SHR);
  309. if (read_block (ctx, at->sbuf, 1))
  310. {
  311. ret = grub_errno;
  312. goto quit;
  313. }
  314. at->save_pos = t;
  315. grub_memcpy (dest, at->sbuf, len);
  316. }
  317. quit:
  318. //ctx->comp.disk->read_hook = 0;
  319. if (ctx->comp.cbuf)
  320. grub_free (ctx->comp.cbuf);
  321. return ret;
  322. }
  323. GRUB_MOD_INIT (ntfscomp)
  324. {
  325. grub_ntfscomp_func = ntfscomp;
  326. }
  327. GRUB_MOD_FINI (ntfscomp)
  328. {
  329. grub_ntfscomp_func = NULL;
  330. }