1 /* ntfscomp.c - compression support for the NTFS filesystem */
3 * Copyright (C) 2007 Free Software Foundation, Inc.
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.
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.
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/>.
19 #include <grub/file.h>
21 #include <grub/misc.h>
22 #include <grub/disk.h>
24 #include <grub/fshelp.h>
25 #include <grub/ntfs.h>
28 decomp_nextvcn (struct grub_ntfs_comp
*cc
)
30 if (cc
->comp_head
>= cc
->comp_tail
)
31 return grub_error (GRUB_ERR_BAD_FS
, "Compression block overflown");
34 (cc
->comp_table
[cc
->comp_head
][1] -
35 (cc
->comp_table
[cc
->comp_head
][0] - cc
->cbuf_vcn
)) * cc
->spc
, 0,
36 cc
->spc
<< BLK_SHR
, cc
->cbuf
))
39 if ((cc
->cbuf_vcn
>= cc
->comp_table
[cc
->comp_head
][0]))
46 decomp_getch (struct grub_ntfs_comp
*cc
, unsigned char *res
)
48 if (cc
->cbuf_ofs
>= (cc
->spc
<< BLK_SHR
))
50 if (decomp_nextvcn (cc
))
53 *res
= (unsigned char) cc
->cbuf
[cc
->cbuf_ofs
++];
58 decomp_get16 (struct grub_ntfs_comp
*cc
, grub_uint16_t
* res
)
62 if ((decomp_getch (cc
, &c1
)) || (decomp_getch (cc
, &c2
)))
64 *res
= ((grub_uint16_t
) c2
) * 256 + ((grub_uint16_t
) c1
);
68 /* Decompress a block (4096 bytes) */
70 decomp_block (struct grub_ntfs_comp
*cc
, char *dest
)
72 grub_uint16_t flg
, cnt
;
74 if (decomp_get16 (cc
, &flg
))
76 cnt
= (flg
& 0xFFF) + 1;
83 grub_uint32_t bits
, copied
;
85 bits
= copied
= tag
= 0;
89 return grub_error (GRUB_ERR_BAD_FS
,
90 "Compression block too large");
94 if (decomp_getch (cc
, &tag
))
104 grub_uint32_t i
, len
, delta
, code
, lmask
, dshift
;
107 if (decomp_get16 (cc
, &word
))
115 grub_error (GRUB_ERR_BAD_FS
, "Context window empty");
119 for (i
= copied
- 1, lmask
= 0xFFF, dshift
= 12; i
>= 0x10;
126 delta
= code
>> dshift
;
127 len
= (code
& lmask
) + 3;
129 for (i
= 0; i
< len
; i
++)
131 dest
[copied
] = dest
[copied
- delta
- 1];
139 if (decomp_getch (cc
, &ch
))
152 return grub_error (GRUB_ERR_BAD_FS
,
153 "Invalid compression block size");
161 n
= (cc
->spc
<< BLK_SHR
) - cc
->cbuf_ofs
;
166 memcpy (dest
, &cc
->cbuf
[cc
->cbuf_ofs
], n
);
171 if ((cnt
) && (decomp_nextvcn (cc
)))
178 read_block (struct grub_ntfs_rlst
*ctx
, char *buf
, int num
)
180 int cpb
= COM_SEC
/ ctx
->comp
.spc
;
186 if ((ctx
->target_vcn
& 0xF) == 0)
189 if (ctx
->comp
.comp_head
!= ctx
->comp
.comp_tail
)
190 return grub_error (GRUB_ERR_BAD_FS
, "Invalid compression block");
191 ctx
->comp
.comp_head
= ctx
->comp
.comp_tail
= 0;
192 ctx
->comp
.cbuf_vcn
= ctx
->target_vcn
;
193 ctx
->comp
.cbuf_ofs
= (ctx
->comp
.spc
<< BLK_SHR
);
194 if (ctx
->target_vcn
>= ctx
->next_vcn
)
196 if (grub_ntfs_read_run_list (ctx
))
199 while (ctx
->target_vcn
+ 16 > ctx
->next_vcn
)
201 if (ctx
->flags
& RF_BLNK
)
203 ctx
->comp
.comp_table
[ctx
->comp
.comp_tail
][0] = ctx
->next_vcn
;
204 ctx
->comp
.comp_table
[ctx
->comp
.comp_tail
][1] =
205 ctx
->curr_lcn
+ ctx
->next_vcn
- ctx
->curr_vcn
;
206 ctx
->comp
.comp_tail
++;
207 if (grub_ntfs_read_run_list (ctx
))
212 nn
= (16 - (ctx
->target_vcn
& 0xF)) / cpb
;
217 if (ctx
->flags
& RF_BLNK
)
219 ctx
->target_vcn
+= nn
* cpb
;
220 if (ctx
->comp
.comp_tail
== 0)
224 grub_memset (buf
, 0, nn
* COM_LEN
);
232 if (decomp_block (&ctx
->comp
, buf
))
243 while ((ctx
->comp
.comp_head
< ctx
->comp
.comp_tail
) && (nn
))
248 ctx
->comp
.comp_table
[ctx
->comp
.comp_head
][0] -
252 ctx
->target_vcn
+= tt
;
257 (ctx
->comp
.comp_table
[ctx
->comp
.comp_head
][1] -
258 (ctx
->comp
.comp_table
[ctx
->comp
.comp_head
][0] -
259 ctx
->target_vcn
)) * ctx
->comp
.spc
, 0,
260 tt
* (ctx
->comp
.spc
<< BLK_SHR
), buf
))
262 buf
+= tt
* (ctx
->comp
.spc
<< BLK_SHR
);
265 if (ctx
->target_vcn
>=
266 ctx
->comp
.comp_table
[ctx
->comp
.comp_head
][0])
267 ctx
->comp
.comp_head
++;
275 (ctx
->target_vcn
- ctx
->curr_vcn
+
276 ctx
->curr_lcn
) * ctx
->comp
.spc
, 0,
277 nn
* (ctx
->comp
.spc
<< BLK_SHR
), buf
))
279 buf
+= nn
* (ctx
->comp
.spc
<< BLK_SHR
);
281 ctx
->target_vcn
+= nn
;
289 ntfscomp (struct grub_ntfs_attr
*at
, char *dest
, grub_uint32_t ofs
,
290 grub_uint32_t len
, struct grub_ntfs_rlst
*ctx
, grub_uint32_t vcn
)
294 ctx
->comp
.comp_head
= ctx
->comp
.comp_tail
= 0;
295 ctx
->comp
.cbuf
= grub_malloc ((ctx
->comp
.spc
) << BLK_SHR
);
301 //ctx->comp.disk->read_hook = read_hook;
303 if ((vcn
> ctx
->target_vcn
) &&
305 (ctx
, NULL
, ((vcn
- ctx
->target_vcn
) * ctx
->comp
.spc
) / COM_SEC
)))
313 grub_uint32_t t
, n
, o
;
315 t
= ctx
->target_vcn
* (ctx
->comp
.spc
<< BLK_SHR
);
316 if (read_block (ctx
, at
->sbuf
, 1))
328 grub_memcpy (dest
, &at
->sbuf
[o
], n
);
335 if (read_block (ctx
, dest
, len
/ COM_LEN
))
341 dest
+= (len
/ COM_LEN
) * COM_LEN
;
347 t
= ctx
->target_vcn
* (ctx
->comp
.spc
<< BLK_SHR
);
348 if (read_block (ctx
, at
->sbuf
, 1))
356 grub_memcpy (dest
, at
->sbuf
, len
);
360 //ctx->comp.disk->read_hook = 0;
362 grub_free (ctx
->comp
.cbuf
);
366 GRUB_MOD_INIT (ntfscomp
)
368 grub_ntfscomp_func
= ntfscomp
;
371 GRUB_MOD_FINI (ntfscomp
)
373 grub_ntfscomp_func
= NULL
;