1 /* ntfs.c - NTFS filesystem */
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2007 Free Software Foundation, Inc.
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include <grub/file.h>
22 #include <grub/misc.h>
23 #include <grub/disk.h>
25 #include <grub/fshelp.h>
26 #include <grub/ntfs.h>
29 static grub_dl_t my_mod
;
32 ntfscomp_func_t grub_ntfscomp_func
;
35 fixup (struct grub_ntfs_data
*data
, char *buf
, int len
, char *magic
)
41 if (grub_memcmp (buf
, magic
, 4))
42 return grub_error (GRUB_ERR_BAD_FS
, "%s label not found", magic
);
44 ss
= u16at (buf
, 6) - 1;
45 if (ss
* (int) data
->blocksize
!= len
* GRUB_DISK_SECTOR_SIZE
)
46 return grub_error (GRUB_ERR_BAD_FS
, "Size not match",
47 ss
* (int) data
->blocksize
,
48 len
* GRUB_DISK_SECTOR_SIZE
);
49 pu
= buf
+ u16at (buf
, 4);
54 buf
+= data
->blocksize
;
56 if (u16at (buf
, 0) != us
)
57 return grub_error (GRUB_ERR_BAD_FS
, "Fixup signature not match");
58 v16at (buf
, 0) = v16at (pu
, 0);
65 static grub_err_t
read_mft (struct grub_ntfs_data
*data
, char *buf
,
67 static grub_err_t
read_attr (struct grub_ntfs_attr
*at
, char *dest
,
68 grub_uint32_t ofs
, grub_uint32_t len
,
71 NESTED_FUNC_ATTR (*read_hook
) (grub_disk_addr_t
76 static grub_err_t
read_data (struct grub_ntfs_attr
*at
, char *pa
, char *dest
,
77 grub_uint32_t ofs
, grub_uint32_t len
,
80 NESTED_FUNC_ATTR (*read_hook
) (grub_disk_addr_t
86 init_attr (struct grub_ntfs_attr
*at
, struct grub_ntfs_file
*mft
)
89 at
->flags
= (mft
== &mft
->data
->mmft
) ? AF_MMFT
: 0;
90 at
->attr_nxt
= mft
->buf
+ u16at (mft
->buf
, 0x14);
91 at
->attr_end
= at
->emft_buf
= at
->edat_buf
= at
->sbuf
= NULL
;
95 free_attr (struct grub_ntfs_attr
*at
)
97 grub_free (at
->emft_buf
);
98 grub_free (at
->edat_buf
);
103 find_attr (struct grub_ntfs_attr
*at
, unsigned char attr
)
105 if (at
->flags
& AF_ALST
)
108 while (at
->attr_nxt
< at
->attr_end
)
110 at
->attr_cur
= at
->attr_nxt
;
111 at
->attr_nxt
+= u16at (at
->attr_cur
, 4);
112 if (((unsigned char) *at
->attr_cur
== attr
) || (attr
== 0))
116 if (at
->flags
& AF_MMFT
)
119 (at
->mft
->data
->disk
, v32at (at
->attr_cur
, 0x10), 0,
123 (at
->mft
->data
->disk
, v32at (at
->attr_cur
, 0x14), 0,
124 512, at
->emft_buf
+ 512)))
128 (at
->mft
->data
, at
->emft_buf
, at
->mft
->data
->mft_size
,
134 if (read_mft (at
->mft
->data
, at
->emft_buf
,
135 u32at (at
->attr_cur
, 0x10)))
139 new_pos
= &at
->emft_buf
[u16at (at
->emft_buf
, 0x14)];
140 while ((unsigned char) *new_pos
!= 0xFF)
142 if (((unsigned char) *new_pos
==
143 (unsigned char) *at
->attr_cur
)
144 && (u16at (new_pos
, 0xE) == u16at (at
->attr_cur
, 0x18)))
148 new_pos
+= u16at (new_pos
, 4);
150 grub_error (GRUB_ERR_BAD_FS
,
151 "Can\'t find 0x%X in attribute list",
152 (unsigned char) *at
->attr_cur
);
158 at
->attr_cur
= at
->attr_nxt
;
159 while ((unsigned char) *at
->attr_cur
!= 0xFF)
161 at
->attr_nxt
+= u16at (at
->attr_cur
, 4);
162 if ((unsigned char) *at
->attr_cur
== AT_ATTRIBUTE_LIST
)
163 at
->attr_end
= at
->attr_cur
;
164 if (((unsigned char) *at
->attr_cur
== attr
) || (attr
== 0))
166 at
->attr_cur
= at
->attr_nxt
;
172 at
->emft_buf
= grub_malloc (at
->mft
->data
->mft_size
<< BLK_SHR
);
173 if (at
->emft_buf
== NULL
)
179 if (u32at (pa
, 0x28) > 4096)
181 grub_error (GRUB_ERR_BAD_FS
,
182 "Non-resident attribute list too large");
185 at
->attr_cur
= at
->attr_end
;
186 at
->edat_buf
= grub_malloc (u32at (pa
, 0x28));
189 if (read_data (at
, pa
, at
->edat_buf
, 0, u32at (pa
, 0x28), 0, 0))
191 grub_error (GRUB_ERR_BAD_FS
,
192 "Fail to read non-resident attribute list");
195 at
->attr_nxt
= at
->edat_buf
;
196 at
->attr_end
= at
->edat_buf
+ u32at (pa
, 0x30);
200 at
->attr_nxt
= at
->attr_end
+ u16at (pa
, 0x14);
201 at
->attr_end
= at
->attr_end
+ u32at (pa
, 4);
203 at
->flags
|= AF_ALST
;
204 while (at
->attr_nxt
< at
->attr_end
)
206 if (((unsigned char) *at
->attr_nxt
== attr
) || (attr
== 0))
208 at
->attr_nxt
+= u16at (at
->attr_nxt
, 4);
210 if (at
->attr_nxt
>= at
->attr_end
)
213 if ((at
->flags
& AF_MMFT
) && (attr
== AT_DATA
))
215 at
->flags
|= AF_GPOS
;
216 at
->attr_cur
= at
->attr_nxt
;
218 v32at (pa
, 0x10) = at
->mft
->data
->mft_start
;
219 v32at (pa
, 0x14) = at
->mft
->data
->mft_start
+ 1;
220 pa
= at
->attr_nxt
+ u16at (pa
, 4);
221 while (pa
< at
->attr_end
)
223 if ((unsigned char) *pa
!= attr
)
227 u32at (pa
, 0x10) * (at
->mft
->data
->mft_size
<< BLK_SHR
),
228 at
->mft
->data
->mft_size
<< BLK_SHR
, 0, 0))
232 at
->attr_nxt
= at
->attr_cur
;
233 at
->flags
&= ~AF_GPOS
;
241 locate_attr (struct grub_ntfs_attr
*at
, struct grub_ntfs_file
*mft
,
247 if ((pa
= find_attr (at
, attr
)) == NULL
)
249 if ((at
->flags
& AF_ALST
) == 0)
253 if ((pa
= find_attr (at
, attr
)) == NULL
)
255 if (at
->flags
& AF_ALST
)
258 grub_errno
= GRUB_ERR_NONE
;
261 pa
= find_attr (at
, attr
);
267 read_run_data (char *run
, int nn
, grub_uint32_t
* val
, int sig
)
276 r
+= v
* (*(unsigned char *) (run
++));
280 if ((sig
) && (r
& (v
>> 1)))
288 grub_ntfs_read_run_list (struct grub_ntfs_rlst
* ctx
)
296 c1
= ((unsigned char) (*run
) & 0xF);
297 c2
= ((unsigned char) (*run
) >> 4);
300 if ((ctx
->attr
) && (ctx
->attr
->flags
& AF_ALST
))
302 void NESTED_FUNC_ATTR (*save_hook
) (grub_disk_addr_t sector
,
306 save_hook
= ctx
->comp
.disk
->read_hook
;
307 ctx
->comp
.disk
->read_hook
= 0;
308 run
= find_attr (ctx
->attr
, (unsigned char) *ctx
->attr
->attr_cur
);
309 ctx
->comp
.disk
->read_hook
= save_hook
;
313 return grub_error (GRUB_ERR_BAD_FS
,
314 "$DATA should be non-resident");
316 run
+= u16at (run
, 0x20);
321 return grub_error (GRUB_ERR_BAD_FS
, "Run list overflown");
323 run
= read_run_data (run
+ 1, c1
, &val
, 0); /* length of current VCN */
324 ctx
->curr_vcn
= ctx
->next_vcn
;
325 ctx
->next_vcn
+= val
;
326 run
= read_run_data (run
, c2
, &val
, 1); /* offset to previous LCN */
327 ctx
->curr_lcn
+= val
;
329 ctx
->flags
|= RF_BLNK
;
331 ctx
->flags
&= ~RF_BLNK
;
337 grub_ntfs_read_block (grub_fshelp_node_t node
, int block
)
339 struct grub_ntfs_rlst
*ctx
;
341 ctx
= (struct grub_ntfs_rlst
*) node
;
342 if ((grub_uint32_t
) block
>= ctx
->next_vcn
)
344 if (grub_ntfs_read_run_list (ctx
))
346 return ctx
->curr_lcn
;
349 return (ctx
->flags
& RF_BLNK
) ? 0 : ((grub_uint32_t
) block
-
350 ctx
->curr_vcn
+ ctx
->curr_lcn
);
354 read_data (struct grub_ntfs_attr
*at
, char *pa
, char *dest
, grub_uint32_t ofs
,
355 grub_uint32_t len
, int cached
,
356 void NESTED_FUNC_ATTR (*read_hook
) (grub_disk_addr_t sector
,
361 struct grub_ntfs_rlst cc
, *ctx
;
366 grub_memset (&cc
, 0, sizeof (cc
));
369 ctx
->comp
.spc
= at
->mft
->data
->spc
;
370 ctx
->comp
.disk
= at
->mft
->data
->disk
;
374 if (ofs
+ len
> u32at (pa
, 0x10))
375 return grub_error (GRUB_ERR_BAD_FS
, "Read out of range");
376 grub_memcpy (dest
, pa
+ u32at (pa
, 0x14) + ofs
, len
);
380 if (u16at (pa
, 0xC) & FLAG_COMPRESSED
)
381 ctx
->flags
|= RF_COMP
;
383 ctx
->flags
&= ~RF_COMP
;
384 ctx
->cur_run
= pa
+ u16at (pa
, 0x20);
386 if (ctx
->flags
& RF_COMP
)
389 return grub_error (GRUB_ERR_BAD_FS
, "Attribute can\'t be compressed");
393 if ((ofs
& (~(COM_LEN
- 1))) == at
->save_pos
)
397 n
= COM_LEN
- (ofs
- at
->save_pos
);
401 grub_memcpy (dest
, at
->sbuf
+ ofs
- at
->save_pos
, n
);
412 at
->sbuf
= grub_malloc (COM_LEN
);
413 if (at
->sbuf
== NULL
)
418 vcn
= ctx
->target_vcn
= (ofs
/ COM_LEN
) * (COM_SEC
/ ctx
->comp
.spc
);
419 ctx
->target_vcn
&= ~0xF;
422 vcn
= ctx
->target_vcn
= (ofs
>> BLK_SHR
) / ctx
->comp
.spc
;
424 ctx
->next_vcn
= u32at (pa
, 0x10);
426 while (ctx
->next_vcn
<= ctx
->target_vcn
)
428 if (grub_ntfs_read_run_list (ctx
))
432 if (at
->flags
& AF_GPOS
)
434 grub_uint32_t st0
, st1
;
437 (ctx
->target_vcn
- ctx
->curr_vcn
+ ctx
->curr_lcn
) * ctx
->comp
.spc
+
438 ((ofs
>> BLK_SHR
) % ctx
->comp
.spc
);
441 (ctx
->next_vcn
- ctx
->curr_vcn
+ ctx
->curr_lcn
) * ctx
->comp
.spc
)
443 if (grub_ntfs_read_run_list (ctx
))
445 st1
= ctx
->curr_lcn
* ctx
->comp
.spc
;
447 v32at (dest
, 0) = st0
;
448 v32at (dest
, 4) = st1
;
452 if (!(ctx
->flags
& RF_COMP
))
456 if (!grub_fshelp_log2blksize (ctx
->comp
.spc
, &pow
))
457 grub_fshelp_read_file (ctx
->comp
.disk
, (grub_fshelp_node_t
) ctx
,
458 read_hook
, ofs
, len
, dest
,
459 grub_ntfs_read_block
, ofs
+ len
, pow
);
463 return (grub_ntfscomp_func
) ? grub_ntfscomp_func (at
, dest
, ofs
, len
, ctx
,
465 grub_error (GRUB_ERR_BAD_FS
, "ntfscomp module not loaded");
469 read_attr (struct grub_ntfs_attr
*at
, char *dest
, grub_uint32_t ofs
,
470 grub_uint32_t len
, int cached
,
471 void NESTED_FUNC_ATTR (*read_hook
) (grub_disk_addr_t sector
,
480 save_cur
= at
->attr_cur
;
481 at
->attr_nxt
= at
->attr_cur
;
482 attr
= (unsigned char) *at
->attr_nxt
;
483 if (at
->flags
& AF_ALST
)
488 vcn
= ofs
/ (at
->mft
->data
->spc
<< BLK_SHR
);
489 pa
= at
->attr_nxt
+ u16at (at
->attr_nxt
, 4);
490 while (pa
< at
->attr_end
)
492 if ((unsigned char) *pa
!= attr
)
494 if (u32at (pa
, 8) > vcn
)
500 pp
= find_attr (at
, attr
);
502 ret
= read_data (at
, pp
, dest
, ofs
, len
, cached
, read_hook
);
505 (grub_errno
) ? grub_errno
: grub_error (GRUB_ERR_BAD_FS
,
506 "Attribute not found");
507 at
->attr_cur
= save_cur
;
512 read_mft (struct grub_ntfs_data
*data
, char *buf
, grub_uint32_t mftno
)
515 (&data
->mmft
.attr
, buf
, mftno
* (data
->mft_size
<< BLK_SHR
),
516 data
->mft_size
<< BLK_SHR
, 0, 0))
517 return grub_error (GRUB_ERR_BAD_FS
, "Read MFT 0x%X fails", mftno
);
518 return fixup (data
, buf
, data
->mft_size
, "FILE");
522 init_file (struct grub_ntfs_file
*mft
, grub_uint32_t mftno
)
528 mft
->buf
= grub_malloc (mft
->data
->mft_size
<< BLK_SHR
);
529 if (mft
->buf
== NULL
)
532 if (read_mft (mft
->data
, mft
->buf
, mftno
))
535 flag
= u16at (mft
->buf
, 0x16);
537 return grub_error (GRUB_ERR_BAD_FS
, "MFT 0x%X is not in use", mftno
);
543 pa
= locate_attr (&mft
->attr
, mft
, AT_DATA
);
545 return grub_error (GRUB_ERR_BAD_FS
, "No $DATA in MFT 0x%X", mftno
);
548 mft
->size
= u32at (pa
, 0x10);
550 mft
->size
= u32at (pa
, 0x30);
552 if ((mft
->attr
.flags
& AF_ALST
) == 0)
553 mft
->attr
.attr_end
= 0; /* Don't jump to attribute list */
556 init_attr (&mft
->attr
, mft
);
562 free_file (struct grub_ntfs_file
*mft
)
564 free_attr (&mft
->attr
);
565 grub_free (mft
->buf
);
569 list_file (struct grub_ntfs_file
*diro
, char *pos
,
571 (*hook
) (const char *filename
,
572 enum grub_fshelp_filetype filetype
,
573 grub_fshelp_node_t node
))
581 if (pos
[0xC] & 2) /* end signature */
585 ns
= (unsigned char) *(np
- 2);
588 enum grub_fshelp_filetype type
;
589 struct grub_ntfs_file
*fdiro
;
593 grub_error (GRUB_ERR_BAD_FS
, "64-bit MFT number");
598 (u32at (pos
, 0x48) & ATTR_DIRECTORY
) ? GRUB_FSHELP_DIR
:
601 fdiro
= grub_malloc (sizeof (struct grub_ntfs_file
));
605 grub_memset (fdiro
, 0, sizeof (*fdiro
));
606 fdiro
->data
= diro
->data
;
607 fdiro
->ino
= u32at (pos
, 0);
609 ustr
= grub_malloc (ns
* 4 + 1);
612 *grub_utf16_to_utf8 ((grub_uint8_t
*) ustr
, (grub_uint16_t
*) np
,
615 if (hook (ustr
, type
, fdiro
))
623 pos
+= u16at (pos
, 8);
629 grub_ntfs_iterate_dir (grub_fshelp_node_t dir
,
631 (*hook
) (const char *filename
,
632 enum grub_fshelp_filetype filetype
,
633 grub_fshelp_node_t node
))
635 unsigned char *bitmap
;
636 struct grub_ntfs_attr attr
, *at
;
637 char *cur_pos
, *indx
, *bmp
;
638 int bitmap_len
, ret
= 0;
639 struct grub_ntfs_file
*mft
;
641 mft
= (struct grub_ntfs_file
*) dir
;
643 if (!mft
->inode_read
)
645 if (init_file (mft
, mft
->ino
))
656 if ((cur_pos
= find_attr (at
, AT_INDEX_ROOT
)) == NULL
)
658 grub_error (GRUB_ERR_BAD_FS
, "No $INDEX_ROOT");
662 /* Resident, Namelen=4, Offset=0x18, Flags=0x00, Name="$I30" */
663 if ((u32at (cur_pos
, 8) != 0x180400) ||
664 (u32at (cur_pos
, 0x18) != 0x490024) ||
665 (u32at (cur_pos
, 0x1C) != 0x300033))
667 cur_pos
+= u16at (cur_pos
, 0x14);
668 if (*cur_pos
!= 0x30) /* Not filename index */
673 cur_pos
+= 0x10; /* Skip index root */
674 ret
= list_file (mft
, cur_pos
+ u16at (cur_pos
, 0), hook
);
682 while ((cur_pos
= find_attr (at
, AT_BITMAP
)) != NULL
)
686 ofs
= (unsigned char) cur_pos
[0xA];
687 /* Namelen=4, Name="$I30" */
688 if ((cur_pos
[9] == 4) &&
689 (u32at (cur_pos
, ofs
) == 0x490024) &&
690 (u32at (cur_pos
, ofs
+ 4) == 0x300033))
692 if ((at
->flags
& AF_ALST
) && (cur_pos
[8] == 0))
694 grub_error (GRUB_ERR_BAD_FS
,
695 "$BITMAP should be non-resident when in attribute list");
700 bitmap
= (unsigned char *) (cur_pos
+ u16at (cur_pos
, 0x14));
701 bitmap_len
= u32at (cur_pos
, 0x10);
704 if (u32at (cur_pos
, 0x28) > BMP_LEN
)
706 grub_error (GRUB_ERR_BAD_FS
, "Non-resident $BITMAP too large");
709 bmp
= grub_malloc (u32at (cur_pos
, 0x28));
713 bitmap
= (unsigned char *) bmp
;
714 bitmap_len
= u32at (cur_pos
, 0x30);
715 if (read_data (at
, cur_pos
, bmp
, 0, u32at (cur_pos
, 0x28), 0, 0))
717 grub_error (GRUB_ERR_BAD_FS
,
718 "Fails to read non-resident $BITMAP");
726 cur_pos
= locate_attr (at
, mft
, AT_INDEX_ALLOCATION
);
727 while (cur_pos
!= NULL
)
729 /* Non-resident, Namelen=4, Offset=0x40, Flags=0, Name="$I30" */
730 if ((u32at (cur_pos
, 8) == 0x400401) &&
731 (u32at (cur_pos
, 0x40) == 0x490024) &&
732 (u32at (cur_pos
, 0x44) == 0x300033))
734 cur_pos
= find_attr (at
, AT_INDEX_ALLOCATION
);
737 if ((!cur_pos
) && (bitmap
))
739 grub_error (GRUB_ERR_BAD_FS
, "$BITMAP without $INDEX_ALLOCATION");
747 indx
= grub_malloc (mft
->data
->idx_size
<< BLK_SHR
);
752 for (i
= 0; i
< (grub_uint32_t
) bitmap_len
* 8; i
++)
757 (at
, indx
, i
* (mft
->data
->idx_size
<< BLK_SHR
),
758 (mft
->data
->idx_size
<< BLK_SHR
), 0, 0))
759 || (fixup (mft
->data
, indx
, mft
->data
->idx_size
, "INDX")))
761 ret
= list_file (mft
, &indx
[0x18 + u16at (indx
, 0x18)], hook
);
782 static struct grub_ntfs_data
*
783 grub_ntfs_mount (grub_disk_t disk
)
785 struct grub_ntfs_bpb bpb
;
786 struct grub_ntfs_data
*data
= 0;
791 data
= (struct grub_ntfs_data
*) grub_malloc (sizeof (*data
));
795 grub_memset (data
, 0, sizeof (*data
));
800 if (grub_disk_read (disk
, 0, 0, sizeof (bpb
), (char *) &bpb
))
803 if (grub_memcmp ((char *) &bpb
.oem_name
, "NTFS", 4))
806 data
->blocksize
= grub_le_to_cpu16 (bpb
.bytes_per_sector
);
807 data
->spc
= bpb
.sectors_per_cluster
* (data
->blocksize
>> BLK_SHR
);
809 if (bpb
.clusters_per_mft
> 0)
810 data
->mft_size
= data
->spc
* bpb
.clusters_per_mft
;
812 data
->mft_size
= 1 << (-bpb
.clusters_per_mft
- BLK_SHR
);
814 if (bpb
.clusters_per_index
> 0)
815 data
->idx_size
= data
->spc
* bpb
.clusters_per_index
;
817 data
->idx_size
= 1 << (-bpb
.clusters_per_index
- BLK_SHR
);
819 data
->mft_start
= grub_le_to_cpu64 (bpb
.mft_lcn
) * data
->spc
;
821 if ((data
->mft_size
> MAX_MFT
) || (data
->idx_size
> MAX_IDX
) ||
822 (data
->spc
> MAX_SPC
) || (data
->spc
> data
->idx_size
))
825 data
->mmft
.data
= data
;
826 data
->cmft
.data
= data
;
828 data
->mmft
.buf
= grub_malloc (data
->mft_size
<< BLK_SHR
);
833 (disk
, data
->mft_start
, 0, data
->mft_size
<< BLK_SHR
, data
->mmft
.buf
))
836 if (fixup (data
, data
->mmft
.buf
, data
->mft_size
, "FILE"))
839 if (!locate_attr (&data
->mmft
.attr
, &data
->mmft
, AT_DATA
))
842 if (init_file (&data
->cmft
, FILE_ROOT
))
848 grub_error (GRUB_ERR_BAD_FS
, "not an ntfs filesystem");
852 free_file (&data
->mmft
);
853 free_file (&data
->cmft
);
859 grub_ntfs_dir (grub_device_t device
, const char *path
,
860 int (*hook
) (const char *filename
, int dir
))
862 struct grub_ntfs_data
*data
= 0;
863 struct grub_fshelp_node
*fdiro
= 0;
865 auto int NESTED_FUNC_ATTR
iterate (const char *filename
,
866 enum grub_fshelp_filetype filetype
,
867 grub_fshelp_node_t node
);
869 int NESTED_FUNC_ATTR
iterate (const char *filename
,
870 enum grub_fshelp_filetype filetype
,
871 grub_fshelp_node_t node
)
875 if (filetype
== GRUB_FSHELP_DIR
)
876 return hook (filename
, 1);
878 return hook (filename
, 0);
884 grub_dl_ref (my_mod
);
888 data
= grub_ntfs_mount (device
->disk
);
892 grub_fshelp_find_file (path
, &data
->cmft
, &fdiro
, grub_ntfs_iterate_dir
,
898 grub_ntfs_iterate_dir (fdiro
, iterate
);
901 if ((fdiro
) && (fdiro
!= &data
->cmft
))
908 free_file (&data
->mmft
);
909 free_file (&data
->cmft
);
914 grub_dl_unref (my_mod
);
921 grub_ntfs_open (grub_file_t file
, const char *name
)
923 struct grub_ntfs_data
*data
= 0;
924 struct grub_fshelp_node
*mft
= 0;
927 grub_dl_ref (my_mod
);
930 data
= grub_ntfs_mount (file
->device
->disk
);
934 grub_fshelp_find_file (name
, &data
->cmft
, &mft
, grub_ntfs_iterate_dir
,
940 if (mft
!= &data
->cmft
)
942 free_file (&data
->cmft
);
943 grub_memcpy (&data
->cmft
, mft
, sizeof (*mft
));
945 if (!data
->cmft
.inode_read
)
947 if (init_file (&data
->cmft
, data
->cmft
.ino
))
952 file
->size
= data
->cmft
.size
;
961 free_file (&data
->mmft
);
962 free_file (&data
->cmft
);
967 grub_dl_unref (my_mod
);
974 grub_ntfs_read (grub_file_t file
, char *buf
, grub_size_t len
)
976 struct grub_ntfs_file
*mft
;
978 mft
= &((struct grub_ntfs_data
*) file
->data
)->cmft
;
980 mft
->attr
.save_pos
= 1;
982 if (file
->offset
> file
->size
)
984 grub_error (GRUB_ERR_BAD_FS
, "Bad offset");
988 if (file
->offset
+ len
> file
->size
)
989 len
= file
->size
- file
->offset
;
991 read_attr (&mft
->attr
, buf
, file
->offset
, len
, 1, file
->read_hook
);
992 return (grub_errno
) ? 0 : len
;
996 grub_ntfs_close (grub_file_t file
)
998 struct grub_ntfs_data
*data
;
1004 free_file (&data
->mmft
);
1005 free_file (&data
->cmft
);
1010 grub_dl_unref (my_mod
);
1017 grub_ntfs_label (grub_device_t device
, char **label
)
1019 struct grub_ntfs_data
*data
= 0;
1020 struct grub_fshelp_node
*mft
= 0;
1024 grub_dl_ref (my_mod
);
1029 data
= grub_ntfs_mount (device
->disk
);
1033 grub_fshelp_find_file ("/$Volume", &data
->cmft
, &mft
, grub_ntfs_iterate_dir
,
1034 0, GRUB_FSHELP_REG
);
1039 if (!mft
->inode_read
)
1041 mft
->buf
= grub_malloc (mft
->data
->mft_size
<< BLK_SHR
);
1042 if (mft
->buf
== NULL
)
1045 if (read_mft (mft
->data
, mft
->buf
, mft
->ino
))
1049 init_attr (&mft
->attr
, mft
);
1050 pa
= find_attr (&mft
->attr
, AT_VOLUME_NAME
);
1051 if ((pa
) && (pa
[8] == 0) && (u32at (pa
, 0x10)))
1056 len
= u32at (pa
, 0x10) / 2;
1057 buf
= grub_malloc (len
* 4 + 1);
1058 pa
+= u16at (pa
, 0x14);
1059 *grub_utf16_to_utf8 ((grub_uint8_t
*) buf
, (grub_uint16_t
*) pa
, len
) =
1065 if ((mft
) && (mft
!= &data
->cmft
))
1072 free_file (&data
->mmft
);
1073 free_file (&data
->cmft
);
1078 grub_dl_unref (my_mod
);
1084 static struct grub_fs grub_ntfs_fs
= {
1086 .dir
= grub_ntfs_dir
,
1087 .open
= grub_ntfs_open
,
1088 .read
= grub_ntfs_read
,
1089 .close
= grub_ntfs_close
,
1090 .label
= grub_ntfs_label
,
1094 GRUB_MOD_INIT (ntfs
)
1096 grub_fs_register (&grub_ntfs_fs
);
1102 GRUB_MOD_FINI (ntfs
)
1104 grub_fs_unregister (&grub_ntfs_fs
);