1 /* ntfs.c - NTFS filesystem */
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2007,2008 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>
28 static grub_dl_t my_mod
;
30 ntfscomp_func_t grub_ntfscomp_func
;
33 fixup (struct grub_ntfs_data
*data
, char *buf
, int len
, char *magic
)
39 if (grub_memcmp (buf
, magic
, 4))
40 return grub_error (GRUB_ERR_BAD_FS
, "%s label not found", magic
);
42 ss
= u16at (buf
, 6) - 1;
43 if (ss
* (int) data
->blocksize
!= len
* GRUB_DISK_SECTOR_SIZE
)
44 return grub_error (GRUB_ERR_BAD_FS
, "Size not match",
45 ss
* (int) data
->blocksize
,
46 len
* GRUB_DISK_SECTOR_SIZE
);
47 pu
= buf
+ u16at (buf
, 4);
52 buf
+= data
->blocksize
;
54 if (u16at (buf
, 0) != us
)
55 return grub_error (GRUB_ERR_BAD_FS
, "Fixup signature not match");
56 v16at (buf
, 0) = v16at (pu
, 0);
63 static grub_err_t
read_mft (struct grub_ntfs_data
*data
, char *buf
,
65 static grub_err_t
read_attr (struct grub_ntfs_attr
*at
, char *dest
,
66 grub_uint32_t ofs
, grub_uint32_t len
,
69 NESTED_FUNC_ATTR (*read_hook
) (grub_disk_addr_t
74 static grub_err_t
read_data (struct grub_ntfs_attr
*at
, char *pa
, char *dest
,
75 grub_uint32_t ofs
, grub_uint32_t len
,
78 NESTED_FUNC_ATTR (*read_hook
) (grub_disk_addr_t
84 init_attr (struct grub_ntfs_attr
*at
, struct grub_ntfs_file
*mft
)
87 at
->flags
= (mft
== &mft
->data
->mmft
) ? AF_MMFT
: 0;
88 at
->attr_nxt
= mft
->buf
+ u16at (mft
->buf
, 0x14);
89 at
->attr_end
= at
->emft_buf
= at
->edat_buf
= at
->sbuf
= NULL
;
93 free_attr (struct grub_ntfs_attr
*at
)
95 grub_free (at
->emft_buf
);
96 grub_free (at
->edat_buf
);
101 find_attr (struct grub_ntfs_attr
*at
, unsigned char attr
)
103 if (at
->flags
& AF_ALST
)
106 while (at
->attr_nxt
< at
->attr_end
)
108 at
->attr_cur
= at
->attr_nxt
;
109 at
->attr_nxt
+= u16at (at
->attr_cur
, 4);
110 if (((unsigned char) *at
->attr_cur
== attr
) || (attr
== 0))
114 if (at
->flags
& AF_MMFT
)
117 (at
->mft
->data
->disk
, v32at (at
->attr_cur
, 0x10), 0,
121 (at
->mft
->data
->disk
, v32at (at
->attr_cur
, 0x14), 0,
122 512, at
->emft_buf
+ 512)))
126 (at
->mft
->data
, at
->emft_buf
, at
->mft
->data
->mft_size
,
132 if (read_mft (at
->mft
->data
, at
->emft_buf
,
133 u32at (at
->attr_cur
, 0x10)))
137 new_pos
= &at
->emft_buf
[u16at (at
->emft_buf
, 0x14)];
138 while ((unsigned char) *new_pos
!= 0xFF)
140 if (((unsigned char) *new_pos
==
141 (unsigned char) *at
->attr_cur
)
142 && (u16at (new_pos
, 0xE) == u16at (at
->attr_cur
, 0x18)))
146 new_pos
+= u16at (new_pos
, 4);
148 grub_error (GRUB_ERR_BAD_FS
,
149 "Can\'t find 0x%X in attribute list",
150 (unsigned char) *at
->attr_cur
);
156 at
->attr_cur
= at
->attr_nxt
;
157 while ((unsigned char) *at
->attr_cur
!= 0xFF)
159 at
->attr_nxt
+= u16at (at
->attr_cur
, 4);
160 if ((unsigned char) *at
->attr_cur
== AT_ATTRIBUTE_LIST
)
161 at
->attr_end
= at
->attr_cur
;
162 if (((unsigned char) *at
->attr_cur
== attr
) || (attr
== 0))
164 at
->attr_cur
= at
->attr_nxt
;
170 at
->emft_buf
= grub_malloc (at
->mft
->data
->mft_size
<< BLK_SHR
);
171 if (at
->emft_buf
== NULL
)
179 n
= ((u32at (pa
, 0x30) + GRUB_DISK_SECTOR_SIZE
- 1)
180 & (~(GRUB_DISK_SECTOR_SIZE
- 1)));
181 at
->attr_cur
= at
->attr_end
;
182 at
->edat_buf
= grub_malloc (n
);
185 if (read_data (at
, pa
, at
->edat_buf
, 0, n
, 0, 0))
187 grub_error (GRUB_ERR_BAD_FS
,
188 "Fail to read non-resident attribute list");
191 at
->attr_nxt
= at
->edat_buf
;
192 at
->attr_end
= at
->edat_buf
+ u32at (pa
, 0x30);
196 at
->attr_nxt
= at
->attr_end
+ u16at (pa
, 0x14);
197 at
->attr_end
= at
->attr_end
+ u32at (pa
, 4);
199 at
->flags
|= AF_ALST
;
200 while (at
->attr_nxt
< at
->attr_end
)
202 if (((unsigned char) *at
->attr_nxt
== attr
) || (attr
== 0))
204 at
->attr_nxt
+= u16at (at
->attr_nxt
, 4);
206 if (at
->attr_nxt
>= at
->attr_end
)
209 if ((at
->flags
& AF_MMFT
) && (attr
== AT_DATA
))
211 at
->flags
|= AF_GPOS
;
212 at
->attr_cur
= at
->attr_nxt
;
214 v32at (pa
, 0x10) = at
->mft
->data
->mft_start
;
215 v32at (pa
, 0x14) = at
->mft
->data
->mft_start
+ 1;
216 pa
= at
->attr_nxt
+ u16at (pa
, 4);
217 while (pa
< at
->attr_end
)
219 if ((unsigned char) *pa
!= attr
)
223 u32at (pa
, 0x10) * (at
->mft
->data
->mft_size
<< BLK_SHR
),
224 at
->mft
->data
->mft_size
<< BLK_SHR
, 0, 0))
228 at
->attr_nxt
= at
->attr_cur
;
229 at
->flags
&= ~AF_GPOS
;
237 locate_attr (struct grub_ntfs_attr
*at
, struct grub_ntfs_file
*mft
,
243 if ((pa
= find_attr (at
, attr
)) == NULL
)
245 if ((at
->flags
& AF_ALST
) == 0)
249 if ((pa
= find_attr (at
, attr
)) == NULL
)
251 if (at
->flags
& AF_ALST
)
254 grub_errno
= GRUB_ERR_NONE
;
257 pa
= find_attr (at
, attr
);
263 read_run_data (char *run
, int nn
, grub_uint32_t
* val
, int sig
)
272 r
+= v
* (*(unsigned char *) (run
++));
276 if ((sig
) && (r
& (v
>> 1)))
284 grub_ntfs_read_run_list (struct grub_ntfs_rlst
* ctx
)
292 c1
= ((unsigned char) (*run
) & 0xF);
293 c2
= ((unsigned char) (*run
) >> 4);
296 if ((ctx
->attr
) && (ctx
->attr
->flags
& AF_ALST
))
298 void NESTED_FUNC_ATTR (*save_hook
) (grub_disk_addr_t sector
,
302 save_hook
= ctx
->comp
.disk
->read_hook
;
303 ctx
->comp
.disk
->read_hook
= 0;
304 run
= find_attr (ctx
->attr
, (unsigned char) *ctx
->attr
->attr_cur
);
305 ctx
->comp
.disk
->read_hook
= save_hook
;
309 return grub_error (GRUB_ERR_BAD_FS
,
310 "$DATA should be non-resident");
312 run
+= u16at (run
, 0x20);
317 return grub_error (GRUB_ERR_BAD_FS
, "Run list overflown");
319 run
= read_run_data (run
+ 1, c1
, &val
, 0); /* length of current VCN */
320 ctx
->curr_vcn
= ctx
->next_vcn
;
321 ctx
->next_vcn
+= val
;
322 run
= read_run_data (run
, c2
, &val
, 1); /* offset to previous LCN */
323 ctx
->curr_lcn
+= val
;
325 ctx
->flags
|= RF_BLNK
;
327 ctx
->flags
&= ~RF_BLNK
;
332 static grub_disk_addr_t
333 grub_ntfs_read_block (grub_fshelp_node_t node
, grub_disk_addr_t block
)
335 struct grub_ntfs_rlst
*ctx
;
337 ctx
= (struct grub_ntfs_rlst
*) node
;
338 if ((grub_uint32_t
) block
>= ctx
->next_vcn
)
340 if (grub_ntfs_read_run_list (ctx
))
342 return ctx
->curr_lcn
;
345 return (ctx
->flags
& RF_BLNK
) ? 0 : ((grub_uint32_t
) block
-
346 ctx
->curr_vcn
+ ctx
->curr_lcn
);
350 read_data (struct grub_ntfs_attr
*at
, char *pa
, char *dest
, grub_uint32_t ofs
,
351 grub_uint32_t len
, int cached
,
352 void NESTED_FUNC_ATTR (*read_hook
) (grub_disk_addr_t sector
,
357 struct grub_ntfs_rlst cc
, *ctx
;
362 grub_memset (&cc
, 0, sizeof (cc
));
365 ctx
->comp
.spc
= at
->mft
->data
->spc
;
366 ctx
->comp
.disk
= at
->mft
->data
->disk
;
370 if (ofs
+ len
> u32at (pa
, 0x10))
371 return grub_error (GRUB_ERR_BAD_FS
, "Read out of range");
372 grub_memcpy (dest
, pa
+ u32at (pa
, 0x14) + ofs
, len
);
376 if (u16at (pa
, 0xC) & FLAG_COMPRESSED
)
377 ctx
->flags
|= RF_COMP
;
379 ctx
->flags
&= ~RF_COMP
;
380 ctx
->cur_run
= pa
+ u16at (pa
, 0x20);
382 if (ctx
->flags
& RF_COMP
)
385 return grub_error (GRUB_ERR_BAD_FS
, "Attribute can\'t be compressed");
389 if ((ofs
& (~(COM_LEN
- 1))) == at
->save_pos
)
393 n
= COM_LEN
- (ofs
- at
->save_pos
);
397 grub_memcpy (dest
, at
->sbuf
+ ofs
- at
->save_pos
, n
);
408 at
->sbuf
= grub_malloc (COM_LEN
);
409 if (at
->sbuf
== NULL
)
414 vcn
= ctx
->target_vcn
= (ofs
/ COM_LEN
) * (COM_SEC
/ ctx
->comp
.spc
);
415 ctx
->target_vcn
&= ~0xF;
418 vcn
= ctx
->target_vcn
= (ofs
>> BLK_SHR
) / ctx
->comp
.spc
;
420 ctx
->next_vcn
= u32at (pa
, 0x10);
422 while (ctx
->next_vcn
<= ctx
->target_vcn
)
424 if (grub_ntfs_read_run_list (ctx
))
428 if (at
->flags
& AF_GPOS
)
430 grub_uint32_t st0
, st1
;
433 (ctx
->target_vcn
- ctx
->curr_vcn
+ ctx
->curr_lcn
) * ctx
->comp
.spc
+
434 ((ofs
>> BLK_SHR
) % ctx
->comp
.spc
);
437 (ctx
->next_vcn
- ctx
->curr_vcn
+ ctx
->curr_lcn
) * ctx
->comp
.spc
)
439 if (grub_ntfs_read_run_list (ctx
))
441 st1
= ctx
->curr_lcn
* ctx
->comp
.spc
;
443 v32at (dest
, 0) = st0
;
444 v32at (dest
, 4) = st1
;
448 if (!(ctx
->flags
& RF_COMP
))
452 if (!grub_fshelp_log2blksize (ctx
->comp
.spc
, &pow
))
453 grub_fshelp_read_file (ctx
->comp
.disk
, (grub_fshelp_node_t
) ctx
,
454 read_hook
, ofs
, len
, dest
,
455 grub_ntfs_read_block
, ofs
+ len
, pow
);
459 return (grub_ntfscomp_func
) ? grub_ntfscomp_func (at
, dest
, ofs
, len
, ctx
,
461 grub_error (GRUB_ERR_BAD_FS
, "ntfscomp module not loaded");
465 read_attr (struct grub_ntfs_attr
*at
, char *dest
, grub_uint32_t ofs
,
466 grub_uint32_t len
, int cached
,
467 void NESTED_FUNC_ATTR (*read_hook
) (grub_disk_addr_t sector
,
476 save_cur
= at
->attr_cur
;
477 at
->attr_nxt
= at
->attr_cur
;
478 attr
= (unsigned char) *at
->attr_nxt
;
479 if (at
->flags
& AF_ALST
)
484 vcn
= ofs
/ (at
->mft
->data
->spc
<< BLK_SHR
);
485 pa
= at
->attr_nxt
+ u16at (at
->attr_nxt
, 4);
486 while (pa
< at
->attr_end
)
488 if ((unsigned char) *pa
!= attr
)
490 if (u32at (pa
, 8) > vcn
)
496 pp
= find_attr (at
, attr
);
498 ret
= read_data (at
, pp
, dest
, ofs
, len
, cached
, read_hook
);
501 (grub_errno
) ? grub_errno
: grub_error (GRUB_ERR_BAD_FS
,
502 "Attribute not found");
503 at
->attr_cur
= save_cur
;
508 read_mft (struct grub_ntfs_data
*data
, char *buf
, grub_uint32_t mftno
)
511 (&data
->mmft
.attr
, buf
, mftno
* (data
->mft_size
<< BLK_SHR
),
512 data
->mft_size
<< BLK_SHR
, 0, 0))
513 return grub_error (GRUB_ERR_BAD_FS
, "Read MFT 0x%X fails", mftno
);
514 return fixup (data
, buf
, data
->mft_size
, "FILE");
518 init_file (struct grub_ntfs_file
*mft
, grub_uint32_t mftno
)
524 mft
->buf
= grub_malloc (mft
->data
->mft_size
<< BLK_SHR
);
525 if (mft
->buf
== NULL
)
528 if (read_mft (mft
->data
, mft
->buf
, mftno
))
531 flag
= u16at (mft
->buf
, 0x16);
533 return grub_error (GRUB_ERR_BAD_FS
, "MFT 0x%X is not in use", mftno
);
539 pa
= locate_attr (&mft
->attr
, mft
, AT_DATA
);
541 return grub_error (GRUB_ERR_BAD_FS
, "No $DATA in MFT 0x%X", mftno
);
544 mft
->size
= u32at (pa
, 0x10);
546 mft
->size
= u32at (pa
, 0x30);
548 if ((mft
->attr
.flags
& AF_ALST
) == 0)
549 mft
->attr
.attr_end
= 0; /* Don't jump to attribute list */
552 init_attr (&mft
->attr
, mft
);
558 free_file (struct grub_ntfs_file
*mft
)
560 free_attr (&mft
->attr
);
561 grub_free (mft
->buf
);
565 list_file (struct grub_ntfs_file
*diro
, char *pos
,
567 (*hook
) (const char *filename
,
568 enum grub_fshelp_filetype filetype
,
569 grub_fshelp_node_t node
))
576 char *ustr
, namespace;
578 if (pos
[0xC] & 2) /* end signature */
582 ns
= (unsigned char) *(np
++);
586 * Ignore files in DOS namespace, as they will reappear as Win32
589 if ((ns
) && (namespace != 2))
591 enum grub_fshelp_filetype type
;
592 struct grub_ntfs_file
*fdiro
;
596 grub_error (GRUB_ERR_BAD_FS
, "64-bit MFT number");
601 (u32at (pos
, 0x48) & ATTR_DIRECTORY
) ? GRUB_FSHELP_DIR
:
604 fdiro
= grub_malloc (sizeof (struct grub_ntfs_file
));
608 grub_memset (fdiro
, 0, sizeof (*fdiro
));
609 fdiro
->data
= diro
->data
;
610 fdiro
->ino
= u32at (pos
, 0);
612 ustr
= grub_malloc (ns
* 4 + 1);
615 *grub_utf16_to_utf8 ((grub_uint8_t
*) ustr
, (grub_uint16_t
*) np
,
619 type
|= GRUB_FSHELP_CASE_INSENSITIVE
;
621 if (hook (ustr
, type
, fdiro
))
629 pos
+= u16at (pos
, 8);
635 grub_ntfs_iterate_dir (grub_fshelp_node_t dir
,
637 (*hook
) (const char *filename
,
638 enum grub_fshelp_filetype filetype
,
639 grub_fshelp_node_t node
))
641 unsigned char *bitmap
;
642 struct grub_ntfs_attr attr
, *at
;
643 char *cur_pos
, *indx
, *bmp
;
644 int bitmap_len
, ret
= 0;
645 struct grub_ntfs_file
*mft
;
647 mft
= (struct grub_ntfs_file
*) dir
;
649 if (!mft
->inode_read
)
651 if (init_file (mft
, mft
->ino
))
662 if ((cur_pos
= find_attr (at
, AT_INDEX_ROOT
)) == NULL
)
664 grub_error (GRUB_ERR_BAD_FS
, "No $INDEX_ROOT");
668 /* Resident, Namelen=4, Offset=0x18, Flags=0x00, Name="$I30" */
669 if ((u32at (cur_pos
, 8) != 0x180400) ||
670 (u32at (cur_pos
, 0x18) != 0x490024) ||
671 (u32at (cur_pos
, 0x1C) != 0x300033))
673 cur_pos
+= u16at (cur_pos
, 0x14);
674 if (*cur_pos
!= 0x30) /* Not filename index */
679 cur_pos
+= 0x10; /* Skip index root */
680 ret
= list_file (mft
, cur_pos
+ u16at (cur_pos
, 0), hook
);
688 while ((cur_pos
= find_attr (at
, AT_BITMAP
)) != NULL
)
692 ofs
= (unsigned char) cur_pos
[0xA];
693 /* Namelen=4, Name="$I30" */
694 if ((cur_pos
[9] == 4) &&
695 (u32at (cur_pos
, ofs
) == 0x490024) &&
696 (u32at (cur_pos
, ofs
+ 4) == 0x300033))
698 int is_resident
= (cur_pos
[8] == 0);
700 bitmap_len
= ((is_resident
) ? u32at (cur_pos
, 0x10) :
701 u32at (cur_pos
, 0x28));
703 bmp
= grub_malloc (bitmap_len
);
709 grub_memcpy (bmp
, (char *) (cur_pos
+ u16at (cur_pos
, 0x14)),
714 if (read_data (at
, cur_pos
, bmp
, 0, bitmap_len
, 0, 0))
716 grub_error (GRUB_ERR_BAD_FS
,
717 "Fails to read non-resident $BITMAP");
720 bitmap_len
= u32at (cur_pos
, 0x30);
723 bitmap
= (unsigned char *) bmp
;
729 cur_pos
= locate_attr (at
, mft
, AT_INDEX_ALLOCATION
);
730 while (cur_pos
!= NULL
)
732 /* Non-resident, Namelen=4, Offset=0x40, Flags=0, Name="$I30" */
733 if ((u32at (cur_pos
, 8) == 0x400401) &&
734 (u32at (cur_pos
, 0x40) == 0x490024) &&
735 (u32at (cur_pos
, 0x44) == 0x300033))
737 cur_pos
= find_attr (at
, AT_INDEX_ALLOCATION
);
740 if ((!cur_pos
) && (bitmap
))
742 grub_error (GRUB_ERR_BAD_FS
, "$BITMAP without $INDEX_ALLOCATION");
750 indx
= grub_malloc (mft
->data
->idx_size
<< BLK_SHR
);
755 for (i
= 0; i
< (grub_uint32_t
) bitmap_len
* 8; i
++)
760 (at
, indx
, i
* (mft
->data
->idx_size
<< BLK_SHR
),
761 (mft
->data
->idx_size
<< BLK_SHR
), 0, 0))
762 || (fixup (mft
->data
, indx
, mft
->data
->idx_size
, "INDX")))
764 ret
= list_file (mft
, &indx
[0x18 + u16at (indx
, 0x18)], hook
);
785 static struct grub_ntfs_data
*
786 grub_ntfs_mount (grub_disk_t disk
)
788 struct grub_ntfs_bpb bpb
;
789 struct grub_ntfs_data
*data
= 0;
794 data
= (struct grub_ntfs_data
*) grub_malloc (sizeof (*data
));
798 grub_memset (data
, 0, sizeof (*data
));
803 if (grub_disk_read (disk
, 0, 0, sizeof (bpb
), &bpb
))
806 if (grub_memcmp ((char *) &bpb
.oem_name
, "NTFS", 4))
809 data
->blocksize
= grub_le_to_cpu16 (bpb
.bytes_per_sector
);
810 data
->spc
= bpb
.sectors_per_cluster
* (data
->blocksize
>> BLK_SHR
);
812 if (bpb
.clusters_per_mft
> 0)
813 data
->mft_size
= data
->spc
* bpb
.clusters_per_mft
;
815 data
->mft_size
= 1 << (-bpb
.clusters_per_mft
- BLK_SHR
);
817 if (bpb
.clusters_per_index
> 0)
818 data
->idx_size
= data
->spc
* bpb
.clusters_per_index
;
820 data
->idx_size
= 1 << (-bpb
.clusters_per_index
- BLK_SHR
);
822 data
->mft_start
= grub_le_to_cpu64 (bpb
.mft_lcn
) * data
->spc
;
824 if ((data
->mft_size
> MAX_MFT
) || (data
->idx_size
> MAX_IDX
))
827 data
->mmft
.data
= data
;
828 data
->cmft
.data
= data
;
830 data
->mmft
.buf
= grub_malloc (data
->mft_size
<< BLK_SHR
);
835 (disk
, data
->mft_start
, 0, data
->mft_size
<< BLK_SHR
, data
->mmft
.buf
))
838 data
->uuid
= grub_le_to_cpu64 (bpb
.num_serial
);
840 if (fixup (data
, data
->mmft
.buf
, data
->mft_size
, "FILE"))
843 if (!locate_attr (&data
->mmft
.attr
, &data
->mmft
, AT_DATA
))
846 if (init_file (&data
->cmft
, FILE_ROOT
))
852 grub_error (GRUB_ERR_BAD_FS
, "not an ntfs filesystem");
856 free_file (&data
->mmft
);
857 free_file (&data
->cmft
);
864 grub_ntfs_dir (grub_device_t device
, const char *path
,
865 int (*hook
) (const char *filename
,
866 const struct grub_dirhook_info
*info
))
868 struct grub_ntfs_data
*data
= 0;
869 struct grub_fshelp_node
*fdiro
= 0;
871 auto int NESTED_FUNC_ATTR
iterate (const char *filename
,
872 enum grub_fshelp_filetype filetype
,
873 grub_fshelp_node_t node
);
875 int NESTED_FUNC_ATTR
iterate (const char *filename
,
876 enum grub_fshelp_filetype filetype
,
877 grub_fshelp_node_t node
)
879 struct grub_dirhook_info info
;
880 grub_memset (&info
, 0, sizeof (info
));
881 info
.dir
= ((filetype
& GRUB_FSHELP_TYPE_MASK
) == GRUB_FSHELP_DIR
);
883 return hook (filename
, &info
);
886 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
);
913 grub_dl_unref (my_mod
);
919 grub_ntfs_open (grub_file_t file
, const char *name
)
921 struct grub_ntfs_data
*data
= 0;
922 struct grub_fshelp_node
*mft
= 0;
924 grub_dl_ref (my_mod
);
926 data
= grub_ntfs_mount (file
->device
->disk
);
930 grub_fshelp_find_file (name
, &data
->cmft
, &mft
, grub_ntfs_iterate_dir
,
936 if (mft
!= &data
->cmft
)
938 free_file (&data
->cmft
);
939 grub_memcpy (&data
->cmft
, mft
, sizeof (*mft
));
941 if (!data
->cmft
.inode_read
)
943 if (init_file (&data
->cmft
, data
->cmft
.ino
))
948 file
->size
= data
->cmft
.size
;
957 free_file (&data
->mmft
);
958 free_file (&data
->cmft
);
962 grub_dl_unref (my_mod
);
968 grub_ntfs_read (grub_file_t file
, char *buf
, grub_size_t len
)
970 struct grub_ntfs_file
*mft
;
972 mft
= &((struct grub_ntfs_data
*) file
->data
)->cmft
;
974 mft
->attr
.save_pos
= 1;
976 if (file
->offset
> file
->size
)
978 grub_error (GRUB_ERR_BAD_FS
, "Bad offset");
982 if (file
->offset
+ len
> file
->size
)
983 len
= file
->size
- file
->offset
;
985 read_attr (&mft
->attr
, buf
, file
->offset
, len
, 1, file
->read_hook
);
986 return (grub_errno
) ? 0 : len
;
990 grub_ntfs_close (grub_file_t file
)
992 struct grub_ntfs_data
*data
;
998 free_file (&data
->mmft
);
999 free_file (&data
->cmft
);
1003 grub_dl_unref (my_mod
);
1009 grub_ntfs_label (grub_device_t device
, char **label
)
1011 struct grub_ntfs_data
*data
= 0;
1012 struct grub_fshelp_node
*mft
= 0;
1015 grub_dl_ref (my_mod
);
1019 data
= grub_ntfs_mount (device
->disk
);
1023 grub_fshelp_find_file ("/$Volume", &data
->cmft
, &mft
, grub_ntfs_iterate_dir
,
1024 0, GRUB_FSHELP_REG
);
1029 if (!mft
->inode_read
)
1031 mft
->buf
= grub_malloc (mft
->data
->mft_size
<< BLK_SHR
);
1032 if (mft
->buf
== NULL
)
1035 if (read_mft (mft
->data
, mft
->buf
, mft
->ino
))
1039 init_attr (&mft
->attr
, mft
);
1040 pa
= find_attr (&mft
->attr
, AT_VOLUME_NAME
);
1041 if ((pa
) && (pa
[8] == 0) && (u32at (pa
, 0x10)))
1046 len
= u32at (pa
, 0x10) / 2;
1047 buf
= grub_malloc (len
* 4 + 1);
1048 pa
+= u16at (pa
, 0x14);
1049 *grub_utf16_to_utf8 ((grub_uint8_t
*) buf
, (grub_uint16_t
*) pa
, len
) =
1055 if ((mft
) && (mft
!= &data
->cmft
))
1062 free_file (&data
->mmft
);
1063 free_file (&data
->cmft
);
1067 grub_dl_unref (my_mod
);
1073 grub_ntfs_uuid (grub_device_t device
, char **uuid
)
1075 struct grub_ntfs_data
*data
;
1076 grub_disk_t disk
= device
->disk
;
1078 grub_dl_ref (my_mod
);
1080 data
= grub_ntfs_mount (disk
);
1083 *uuid
= grub_malloc (16 + sizeof ('\0'));
1084 grub_sprintf (*uuid
, "%016llx", (unsigned long long) data
->uuid
);
1089 grub_dl_unref (my_mod
);
1096 static struct grub_fs grub_ntfs_fs
= {
1098 .dir
= grub_ntfs_dir
,
1099 .open
= grub_ntfs_open
,
1100 .read
= grub_ntfs_read
,
1101 .close
= grub_ntfs_close
,
1102 .label
= grub_ntfs_label
,
1103 .uuid
= grub_ntfs_uuid
,
1107 GRUB_MOD_INIT (ntfs
)
1109 grub_fs_register (&grub_ntfs_fs
);
1113 GRUB_MOD_FINI (ntfs
)
1115 grub_fs_unregister (&grub_ntfs_fs
);