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_zalloc (sizeof (struct grub_ntfs_file
));
608 fdiro
->data
= diro
->data
;
609 fdiro
->ino
= u32at (pos
, 0);
611 ustr
= grub_malloc (ns
* 4 + 1);
614 *grub_utf16_to_utf8 ((grub_uint8_t
*) ustr
, (grub_uint16_t
*) np
,
618 type
|= GRUB_FSHELP_CASE_INSENSITIVE
;
620 if (hook (ustr
, type
, fdiro
))
628 pos
+= u16at (pos
, 8);
634 grub_ntfs_iterate_dir (grub_fshelp_node_t dir
,
636 (*hook
) (const char *filename
,
637 enum grub_fshelp_filetype filetype
,
638 grub_fshelp_node_t node
))
640 unsigned char *bitmap
;
641 struct grub_ntfs_attr attr
, *at
;
642 char *cur_pos
, *indx
, *bmp
;
643 int bitmap_len
, ret
= 0;
644 struct grub_ntfs_file
*mft
;
646 mft
= (struct grub_ntfs_file
*) dir
;
648 if (!mft
->inode_read
)
650 if (init_file (mft
, mft
->ino
))
661 if ((cur_pos
= find_attr (at
, AT_INDEX_ROOT
)) == NULL
)
663 grub_error (GRUB_ERR_BAD_FS
, "No $INDEX_ROOT");
667 /* Resident, Namelen=4, Offset=0x18, Flags=0x00, Name="$I30" */
668 if ((u32at (cur_pos
, 8) != 0x180400) ||
669 (u32at (cur_pos
, 0x18) != 0x490024) ||
670 (u32at (cur_pos
, 0x1C) != 0x300033))
672 cur_pos
+= u16at (cur_pos
, 0x14);
673 if (*cur_pos
!= 0x30) /* Not filename index */
678 cur_pos
+= 0x10; /* Skip index root */
679 ret
= list_file (mft
, cur_pos
+ u16at (cur_pos
, 0), hook
);
687 while ((cur_pos
= find_attr (at
, AT_BITMAP
)) != NULL
)
691 ofs
= (unsigned char) cur_pos
[0xA];
692 /* Namelen=4, Name="$I30" */
693 if ((cur_pos
[9] == 4) &&
694 (u32at (cur_pos
, ofs
) == 0x490024) &&
695 (u32at (cur_pos
, ofs
+ 4) == 0x300033))
697 int is_resident
= (cur_pos
[8] == 0);
699 bitmap_len
= ((is_resident
) ? u32at (cur_pos
, 0x10) :
700 u32at (cur_pos
, 0x28));
702 bmp
= grub_malloc (bitmap_len
);
708 grub_memcpy (bmp
, (char *) (cur_pos
+ u16at (cur_pos
, 0x14)),
713 if (read_data (at
, cur_pos
, bmp
, 0, bitmap_len
, 0, 0))
715 grub_error (GRUB_ERR_BAD_FS
,
716 "Fails to read non-resident $BITMAP");
719 bitmap_len
= u32at (cur_pos
, 0x30);
722 bitmap
= (unsigned char *) bmp
;
728 cur_pos
= locate_attr (at
, mft
, AT_INDEX_ALLOCATION
);
729 while (cur_pos
!= NULL
)
731 /* Non-resident, Namelen=4, Offset=0x40, Flags=0, Name="$I30" */
732 if ((u32at (cur_pos
, 8) == 0x400401) &&
733 (u32at (cur_pos
, 0x40) == 0x490024) &&
734 (u32at (cur_pos
, 0x44) == 0x300033))
736 cur_pos
= find_attr (at
, AT_INDEX_ALLOCATION
);
739 if ((!cur_pos
) && (bitmap
))
741 grub_error (GRUB_ERR_BAD_FS
, "$BITMAP without $INDEX_ALLOCATION");
749 indx
= grub_malloc (mft
->data
->idx_size
<< BLK_SHR
);
754 for (i
= 0; i
< (grub_uint32_t
) bitmap_len
* 8; i
++)
759 (at
, indx
, i
* (mft
->data
->idx_size
<< BLK_SHR
),
760 (mft
->data
->idx_size
<< BLK_SHR
), 0, 0))
761 || (fixup (mft
->data
, indx
, mft
->data
->idx_size
, "INDX")))
763 ret
= list_file (mft
, &indx
[0x18 + u16at (indx
, 0x18)], hook
);
784 static struct grub_ntfs_data
*
785 grub_ntfs_mount (grub_disk_t disk
)
787 struct grub_ntfs_bpb bpb
;
788 struct grub_ntfs_data
*data
= 0;
793 data
= (struct grub_ntfs_data
*) grub_zalloc (sizeof (*data
));
800 if (grub_disk_read (disk
, 0, 0, sizeof (bpb
), &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
))
824 data
->mmft
.data
= data
;
825 data
->cmft
.data
= data
;
827 data
->mmft
.buf
= grub_malloc (data
->mft_size
<< BLK_SHR
);
832 (disk
, data
->mft_start
, 0, data
->mft_size
<< BLK_SHR
, data
->mmft
.buf
))
835 data
->uuid
= grub_le_to_cpu64 (bpb
.num_serial
);
837 if (fixup (data
, data
->mmft
.buf
, data
->mft_size
, "FILE"))
840 if (!locate_attr (&data
->mmft
.attr
, &data
->mmft
, AT_DATA
))
843 if (init_file (&data
->cmft
, FILE_ROOT
))
849 grub_error (GRUB_ERR_BAD_FS
, "not an ntfs filesystem");
853 free_file (&data
->mmft
);
854 free_file (&data
->cmft
);
861 grub_ntfs_dir (grub_device_t device
, const char *path
,
862 int (*hook
) (const char *filename
,
863 const struct grub_dirhook_info
*info
))
865 struct grub_ntfs_data
*data
= 0;
866 struct grub_fshelp_node
*fdiro
= 0;
868 auto int NESTED_FUNC_ATTR
iterate (const char *filename
,
869 enum grub_fshelp_filetype filetype
,
870 grub_fshelp_node_t node
);
872 int NESTED_FUNC_ATTR
iterate (const char *filename
,
873 enum grub_fshelp_filetype filetype
,
874 grub_fshelp_node_t node
)
876 struct grub_dirhook_info info
;
877 grub_memset (&info
, 0, sizeof (info
));
878 info
.dir
= ((filetype
& GRUB_FSHELP_TYPE_MASK
) == GRUB_FSHELP_DIR
);
880 return hook (filename
, &info
);
883 grub_dl_ref (my_mod
);
885 data
= grub_ntfs_mount (device
->disk
);
889 grub_fshelp_find_file (path
, &data
->cmft
, &fdiro
, grub_ntfs_iterate_dir
,
895 grub_ntfs_iterate_dir (fdiro
, iterate
);
898 if ((fdiro
) && (fdiro
!= &data
->cmft
))
905 free_file (&data
->mmft
);
906 free_file (&data
->cmft
);
910 grub_dl_unref (my_mod
);
916 grub_ntfs_open (grub_file_t file
, const char *name
)
918 struct grub_ntfs_data
*data
= 0;
919 struct grub_fshelp_node
*mft
= 0;
921 grub_dl_ref (my_mod
);
923 data
= grub_ntfs_mount (file
->device
->disk
);
927 grub_fshelp_find_file (name
, &data
->cmft
, &mft
, grub_ntfs_iterate_dir
,
933 if (mft
!= &data
->cmft
)
935 free_file (&data
->cmft
);
936 grub_memcpy (&data
->cmft
, mft
, sizeof (*mft
));
938 if (!data
->cmft
.inode_read
)
940 if (init_file (&data
->cmft
, data
->cmft
.ino
))
945 file
->size
= data
->cmft
.size
;
954 free_file (&data
->mmft
);
955 free_file (&data
->cmft
);
959 grub_dl_unref (my_mod
);
965 grub_ntfs_read (grub_file_t file
, char *buf
, grub_size_t len
)
967 struct grub_ntfs_file
*mft
;
969 mft
= &((struct grub_ntfs_data
*) file
->data
)->cmft
;
971 mft
->attr
.save_pos
= 1;
973 if (file
->offset
> file
->size
)
975 grub_error (GRUB_ERR_BAD_FS
, "Bad offset");
979 if (file
->offset
+ len
> file
->size
)
980 len
= file
->size
- file
->offset
;
982 read_attr (&mft
->attr
, buf
, file
->offset
, len
, 1, file
->read_hook
);
983 return (grub_errno
) ? 0 : len
;
987 grub_ntfs_close (grub_file_t file
)
989 struct grub_ntfs_data
*data
;
995 free_file (&data
->mmft
);
996 free_file (&data
->cmft
);
1000 grub_dl_unref (my_mod
);
1006 grub_ntfs_label (grub_device_t device
, char **label
)
1008 struct grub_ntfs_data
*data
= 0;
1009 struct grub_fshelp_node
*mft
= 0;
1012 grub_dl_ref (my_mod
);
1016 data
= grub_ntfs_mount (device
->disk
);
1020 grub_fshelp_find_file ("/$Volume", &data
->cmft
, &mft
, grub_ntfs_iterate_dir
,
1021 0, GRUB_FSHELP_REG
);
1026 if (!mft
->inode_read
)
1028 mft
->buf
= grub_malloc (mft
->data
->mft_size
<< BLK_SHR
);
1029 if (mft
->buf
== NULL
)
1032 if (read_mft (mft
->data
, mft
->buf
, mft
->ino
))
1036 init_attr (&mft
->attr
, mft
);
1037 pa
= find_attr (&mft
->attr
, AT_VOLUME_NAME
);
1038 if ((pa
) && (pa
[8] == 0) && (u32at (pa
, 0x10)))
1043 len
= u32at (pa
, 0x10) / 2;
1044 buf
= grub_malloc (len
* 4 + 1);
1045 pa
+= u16at (pa
, 0x14);
1046 *grub_utf16_to_utf8 ((grub_uint8_t
*) buf
, (grub_uint16_t
*) pa
, len
) =
1052 if ((mft
) && (mft
!= &data
->cmft
))
1059 free_file (&data
->mmft
);
1060 free_file (&data
->cmft
);
1064 grub_dl_unref (my_mod
);
1070 grub_ntfs_uuid (grub_device_t device
, char **uuid
)
1072 struct grub_ntfs_data
*data
;
1073 grub_disk_t disk
= device
->disk
;
1075 grub_dl_ref (my_mod
);
1077 data
= grub_ntfs_mount (disk
);
1080 *uuid
= grub_malloc (16 + sizeof ('\0'));
1081 grub_sprintf (*uuid
, "%016llx", (unsigned long long) data
->uuid
);
1086 grub_dl_unref (my_mod
);
1093 static struct grub_fs grub_ntfs_fs
= {
1095 .dir
= grub_ntfs_dir
,
1096 .open
= grub_ntfs_open
,
1097 .read
= grub_ntfs_read
,
1098 .close
= grub_ntfs_close
,
1099 .label
= grub_ntfs_label
,
1100 .uuid
= grub_ntfs_uuid
,
1104 GRUB_MOD_INIT (ntfs
)
1106 grub_fs_register (&grub_ntfs_fs
);
1110 GRUB_MOD_FINI (ntfs
)
1112 grub_fs_unregister (&grub_ntfs_fs
);