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>
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
)
181 n
= ((u32at (pa
, 0x30) + GRUB_DISK_SECTOR_SIZE
- 1)
182 & (~(GRUB_DISK_SECTOR_SIZE
- 1)));
183 at
->attr_cur
= at
->attr_end
;
184 at
->edat_buf
= grub_malloc (n
);
187 if (read_data (at
, pa
, at
->edat_buf
, 0, n
, 0, 0))
189 grub_error (GRUB_ERR_BAD_FS
,
190 "Fail to read non-resident attribute list");
193 at
->attr_nxt
= at
->edat_buf
;
194 at
->attr_end
= at
->edat_buf
+ u32at (pa
, 0x30);
198 at
->attr_nxt
= at
->attr_end
+ u16at (pa
, 0x14);
199 at
->attr_end
= at
->attr_end
+ u32at (pa
, 4);
201 at
->flags
|= AF_ALST
;
202 while (at
->attr_nxt
< at
->attr_end
)
204 if (((unsigned char) *at
->attr_nxt
== attr
) || (attr
== 0))
206 at
->attr_nxt
+= u16at (at
->attr_nxt
, 4);
208 if (at
->attr_nxt
>= at
->attr_end
)
211 if ((at
->flags
& AF_MMFT
) && (attr
== AT_DATA
))
213 at
->flags
|= AF_GPOS
;
214 at
->attr_cur
= at
->attr_nxt
;
216 v32at (pa
, 0x10) = at
->mft
->data
->mft_start
;
217 v32at (pa
, 0x14) = at
->mft
->data
->mft_start
+ 1;
218 pa
= at
->attr_nxt
+ u16at (pa
, 4);
219 while (pa
< at
->attr_end
)
221 if ((unsigned char) *pa
!= attr
)
225 u32at (pa
, 0x10) * (at
->mft
->data
->mft_size
<< BLK_SHR
),
226 at
->mft
->data
->mft_size
<< BLK_SHR
, 0, 0))
230 at
->attr_nxt
= at
->attr_cur
;
231 at
->flags
&= ~AF_GPOS
;
239 locate_attr (struct grub_ntfs_attr
*at
, struct grub_ntfs_file
*mft
,
245 if ((pa
= find_attr (at
, attr
)) == NULL
)
247 if ((at
->flags
& AF_ALST
) == 0)
251 if ((pa
= find_attr (at
, attr
)) == NULL
)
253 if (at
->flags
& AF_ALST
)
256 grub_errno
= GRUB_ERR_NONE
;
259 pa
= find_attr (at
, attr
);
265 read_run_data (char *run
, int nn
, grub_uint32_t
* val
, int sig
)
274 r
+= v
* (*(unsigned char *) (run
++));
278 if ((sig
) && (r
& (v
>> 1)))
286 grub_ntfs_read_run_list (struct grub_ntfs_rlst
* ctx
)
294 c1
= ((unsigned char) (*run
) & 0xF);
295 c2
= ((unsigned char) (*run
) >> 4);
298 if ((ctx
->attr
) && (ctx
->attr
->flags
& AF_ALST
))
300 void NESTED_FUNC_ATTR (*save_hook
) (grub_disk_addr_t sector
,
304 save_hook
= ctx
->comp
.disk
->read_hook
;
305 ctx
->comp
.disk
->read_hook
= 0;
306 run
= find_attr (ctx
->attr
, (unsigned char) *ctx
->attr
->attr_cur
);
307 ctx
->comp
.disk
->read_hook
= save_hook
;
311 return grub_error (GRUB_ERR_BAD_FS
,
312 "$DATA should be non-resident");
314 run
+= u16at (run
, 0x20);
319 return grub_error (GRUB_ERR_BAD_FS
, "Run list overflown");
321 run
= read_run_data (run
+ 1, c1
, &val
, 0); /* length of current VCN */
322 ctx
->curr_vcn
= ctx
->next_vcn
;
323 ctx
->next_vcn
+= val
;
324 run
= read_run_data (run
, c2
, &val
, 1); /* offset to previous LCN */
325 ctx
->curr_lcn
+= val
;
327 ctx
->flags
|= RF_BLNK
;
329 ctx
->flags
&= ~RF_BLNK
;
334 static grub_disk_addr_t
335 grub_ntfs_read_block (grub_fshelp_node_t node
, grub_disk_addr_t block
)
337 struct grub_ntfs_rlst
*ctx
;
339 ctx
= (struct grub_ntfs_rlst
*) node
;
340 if ((grub_uint32_t
) block
>= ctx
->next_vcn
)
342 if (grub_ntfs_read_run_list (ctx
))
344 return ctx
->curr_lcn
;
347 return (ctx
->flags
& RF_BLNK
) ? 0 : ((grub_uint32_t
) block
-
348 ctx
->curr_vcn
+ ctx
->curr_lcn
);
352 read_data (struct grub_ntfs_attr
*at
, char *pa
, char *dest
, grub_uint32_t ofs
,
353 grub_uint32_t len
, int cached
,
354 void NESTED_FUNC_ATTR (*read_hook
) (grub_disk_addr_t sector
,
359 struct grub_ntfs_rlst cc
, *ctx
;
364 grub_memset (&cc
, 0, sizeof (cc
));
367 ctx
->comp
.spc
= at
->mft
->data
->spc
;
368 ctx
->comp
.disk
= at
->mft
->data
->disk
;
372 if (ofs
+ len
> u32at (pa
, 0x10))
373 return grub_error (GRUB_ERR_BAD_FS
, "Read out of range");
374 grub_memcpy (dest
, pa
+ u32at (pa
, 0x14) + ofs
, len
);
378 if (u16at (pa
, 0xC) & FLAG_COMPRESSED
)
379 ctx
->flags
|= RF_COMP
;
381 ctx
->flags
&= ~RF_COMP
;
382 ctx
->cur_run
= pa
+ u16at (pa
, 0x20);
384 if (ctx
->flags
& RF_COMP
)
387 return grub_error (GRUB_ERR_BAD_FS
, "Attribute can\'t be compressed");
391 if ((ofs
& (~(COM_LEN
- 1))) == at
->save_pos
)
395 n
= COM_LEN
- (ofs
- at
->save_pos
);
399 grub_memcpy (dest
, at
->sbuf
+ ofs
- at
->save_pos
, n
);
410 at
->sbuf
= grub_malloc (COM_LEN
);
411 if (at
->sbuf
== NULL
)
416 vcn
= ctx
->target_vcn
= (ofs
/ COM_LEN
) * (COM_SEC
/ ctx
->comp
.spc
);
417 ctx
->target_vcn
&= ~0xF;
420 vcn
= ctx
->target_vcn
= (ofs
>> BLK_SHR
) / ctx
->comp
.spc
;
422 ctx
->next_vcn
= u32at (pa
, 0x10);
424 while (ctx
->next_vcn
<= ctx
->target_vcn
)
426 if (grub_ntfs_read_run_list (ctx
))
430 if (at
->flags
& AF_GPOS
)
432 grub_uint32_t st0
, st1
;
435 (ctx
->target_vcn
- ctx
->curr_vcn
+ ctx
->curr_lcn
) * ctx
->comp
.spc
+
436 ((ofs
>> BLK_SHR
) % ctx
->comp
.spc
);
439 (ctx
->next_vcn
- ctx
->curr_vcn
+ ctx
->curr_lcn
) * ctx
->comp
.spc
)
441 if (grub_ntfs_read_run_list (ctx
))
443 st1
= ctx
->curr_lcn
* ctx
->comp
.spc
;
445 v32at (dest
, 0) = st0
;
446 v32at (dest
, 4) = st1
;
450 if (!(ctx
->flags
& RF_COMP
))
454 if (!grub_fshelp_log2blksize (ctx
->comp
.spc
, &pow
))
455 grub_fshelp_read_file (ctx
->comp
.disk
, (grub_fshelp_node_t
) ctx
,
456 read_hook
, ofs
, len
, dest
,
457 grub_ntfs_read_block
, ofs
+ len
, pow
);
461 return (grub_ntfscomp_func
) ? grub_ntfscomp_func (at
, dest
, ofs
, len
, ctx
,
463 grub_error (GRUB_ERR_BAD_FS
, "ntfscomp module not loaded");
467 read_attr (struct grub_ntfs_attr
*at
, char *dest
, grub_uint32_t ofs
,
468 grub_uint32_t len
, int cached
,
469 void NESTED_FUNC_ATTR (*read_hook
) (grub_disk_addr_t sector
,
478 save_cur
= at
->attr_cur
;
479 at
->attr_nxt
= at
->attr_cur
;
480 attr
= (unsigned char) *at
->attr_nxt
;
481 if (at
->flags
& AF_ALST
)
486 vcn
= ofs
/ (at
->mft
->data
->spc
<< BLK_SHR
);
487 pa
= at
->attr_nxt
+ u16at (at
->attr_nxt
, 4);
488 while (pa
< at
->attr_end
)
490 if ((unsigned char) *pa
!= attr
)
492 if (u32at (pa
, 8) > vcn
)
498 pp
= find_attr (at
, attr
);
500 ret
= read_data (at
, pp
, dest
, ofs
, len
, cached
, read_hook
);
503 (grub_errno
) ? grub_errno
: grub_error (GRUB_ERR_BAD_FS
,
504 "Attribute not found");
505 at
->attr_cur
= save_cur
;
510 read_mft (struct grub_ntfs_data
*data
, char *buf
, grub_uint32_t mftno
)
513 (&data
->mmft
.attr
, buf
, mftno
* (data
->mft_size
<< BLK_SHR
),
514 data
->mft_size
<< BLK_SHR
, 0, 0))
515 return grub_error (GRUB_ERR_BAD_FS
, "Read MFT 0x%X fails", mftno
);
516 return fixup (data
, buf
, data
->mft_size
, "FILE");
520 init_file (struct grub_ntfs_file
*mft
, grub_uint32_t mftno
)
526 mft
->buf
= grub_malloc (mft
->data
->mft_size
<< BLK_SHR
);
527 if (mft
->buf
== NULL
)
530 if (read_mft (mft
->data
, mft
->buf
, mftno
))
533 flag
= u16at (mft
->buf
, 0x16);
535 return grub_error (GRUB_ERR_BAD_FS
, "MFT 0x%X is not in use", mftno
);
541 pa
= locate_attr (&mft
->attr
, mft
, AT_DATA
);
543 return grub_error (GRUB_ERR_BAD_FS
, "No $DATA in MFT 0x%X", mftno
);
546 mft
->size
= u32at (pa
, 0x10);
548 mft
->size
= u32at (pa
, 0x30);
550 if ((mft
->attr
.flags
& AF_ALST
) == 0)
551 mft
->attr
.attr_end
= 0; /* Don't jump to attribute list */
554 init_attr (&mft
->attr
, mft
);
560 free_file (struct grub_ntfs_file
*mft
)
562 free_attr (&mft
->attr
);
563 grub_free (mft
->buf
);
567 list_file (struct grub_ntfs_file
*diro
, char *pos
,
569 (*hook
) (const char *filename
,
570 enum grub_fshelp_filetype filetype
,
571 grub_fshelp_node_t node
))
579 if (pos
[0xC] & 2) /* end signature */
583 ns
= (unsigned char) *(np
- 2);
586 enum grub_fshelp_filetype type
;
587 struct grub_ntfs_file
*fdiro
;
591 grub_error (GRUB_ERR_BAD_FS
, "64-bit MFT number");
596 (u32at (pos
, 0x48) & ATTR_DIRECTORY
) ? GRUB_FSHELP_DIR
:
599 fdiro
= grub_malloc (sizeof (struct grub_ntfs_file
));
603 grub_memset (fdiro
, 0, sizeof (*fdiro
));
604 fdiro
->data
= diro
->data
;
605 fdiro
->ino
= u32at (pos
, 0);
607 ustr
= grub_malloc (ns
* 4 + 1);
610 *grub_utf16_to_utf8 ((grub_uint8_t
*) ustr
, (grub_uint16_t
*) np
,
613 if (hook (ustr
, type
, fdiro
))
621 pos
+= u16at (pos
, 8);
627 grub_ntfs_iterate_dir (grub_fshelp_node_t dir
,
629 (*hook
) (const char *filename
,
630 enum grub_fshelp_filetype filetype
,
631 grub_fshelp_node_t node
))
633 unsigned char *bitmap
;
634 struct grub_ntfs_attr attr
, *at
;
635 char *cur_pos
, *indx
, *bmp
;
636 int bitmap_len
, ret
= 0;
637 struct grub_ntfs_file
*mft
;
639 mft
= (struct grub_ntfs_file
*) dir
;
641 if (!mft
->inode_read
)
643 if (init_file (mft
, mft
->ino
))
654 if ((cur_pos
= find_attr (at
, AT_INDEX_ROOT
)) == NULL
)
656 grub_error (GRUB_ERR_BAD_FS
, "No $INDEX_ROOT");
660 /* Resident, Namelen=4, Offset=0x18, Flags=0x00, Name="$I30" */
661 if ((u32at (cur_pos
, 8) != 0x180400) ||
662 (u32at (cur_pos
, 0x18) != 0x490024) ||
663 (u32at (cur_pos
, 0x1C) != 0x300033))
665 cur_pos
+= u16at (cur_pos
, 0x14);
666 if (*cur_pos
!= 0x30) /* Not filename index */
671 cur_pos
+= 0x10; /* Skip index root */
672 ret
= list_file (mft
, cur_pos
+ u16at (cur_pos
, 0), hook
);
680 while ((cur_pos
= find_attr (at
, AT_BITMAP
)) != NULL
)
684 ofs
= (unsigned char) cur_pos
[0xA];
685 /* Namelen=4, Name="$I30" */
686 if ((cur_pos
[9] == 4) &&
687 (u32at (cur_pos
, ofs
) == 0x490024) &&
688 (u32at (cur_pos
, ofs
+ 4) == 0x300033))
690 if ((at
->flags
& AF_ALST
) && (cur_pos
[8] == 0))
692 grub_error (GRUB_ERR_BAD_FS
,
693 "$BITMAP should be non-resident when in attribute list");
698 bitmap
= (unsigned char *) (cur_pos
+ u16at (cur_pos
, 0x14));
699 bitmap_len
= u32at (cur_pos
, 0x10);
702 if (u32at (cur_pos
, 0x28) > BMP_LEN
)
704 grub_error (GRUB_ERR_BAD_FS
, "Non-resident $BITMAP too large");
707 bmp
= grub_malloc (u32at (cur_pos
, 0x28));
711 bitmap
= (unsigned char *) bmp
;
712 bitmap_len
= u32at (cur_pos
, 0x30);
713 if (read_data (at
, cur_pos
, bmp
, 0, u32at (cur_pos
, 0x28), 0, 0))
715 grub_error (GRUB_ERR_BAD_FS
,
716 "Fails to read non-resident $BITMAP");
724 cur_pos
= locate_attr (at
, mft
, AT_INDEX_ALLOCATION
);
725 while (cur_pos
!= NULL
)
727 /* Non-resident, Namelen=4, Offset=0x40, Flags=0, Name="$I30" */
728 if ((u32at (cur_pos
, 8) == 0x400401) &&
729 (u32at (cur_pos
, 0x40) == 0x490024) &&
730 (u32at (cur_pos
, 0x44) == 0x300033))
732 cur_pos
= find_attr (at
, AT_INDEX_ALLOCATION
);
735 if ((!cur_pos
) && (bitmap
))
737 grub_error (GRUB_ERR_BAD_FS
, "$BITMAP without $INDEX_ALLOCATION");
745 indx
= grub_malloc (mft
->data
->idx_size
<< BLK_SHR
);
750 for (i
= 0; i
< (grub_uint32_t
) bitmap_len
* 8; i
++)
755 (at
, indx
, i
* (mft
->data
->idx_size
<< BLK_SHR
),
756 (mft
->data
->idx_size
<< BLK_SHR
), 0, 0))
757 || (fixup (mft
->data
, indx
, mft
->data
->idx_size
, "INDX")))
759 ret
= list_file (mft
, &indx
[0x18 + u16at (indx
, 0x18)], hook
);
780 static struct grub_ntfs_data
*
781 grub_ntfs_mount (grub_disk_t disk
)
783 struct grub_ntfs_bpb bpb
;
784 struct grub_ntfs_data
*data
= 0;
789 data
= (struct grub_ntfs_data
*) grub_malloc (sizeof (*data
));
793 grub_memset (data
, 0, sizeof (*data
));
798 if (grub_disk_read (disk
, 0, 0, sizeof (bpb
), (char *) &bpb
))
801 if (grub_memcmp ((char *) &bpb
.oem_name
, "NTFS", 4))
804 data
->blocksize
= grub_le_to_cpu16 (bpb
.bytes_per_sector
);
805 data
->spc
= bpb
.sectors_per_cluster
* (data
->blocksize
>> BLK_SHR
);
807 if (bpb
.clusters_per_mft
> 0)
808 data
->mft_size
= data
->spc
* bpb
.clusters_per_mft
;
810 data
->mft_size
= 1 << (-bpb
.clusters_per_mft
- BLK_SHR
);
812 if (bpb
.clusters_per_index
> 0)
813 data
->idx_size
= data
->spc
* bpb
.clusters_per_index
;
815 data
->idx_size
= 1 << (-bpb
.clusters_per_index
- BLK_SHR
);
817 data
->mft_start
= grub_le_to_cpu64 (bpb
.mft_lcn
) * data
->spc
;
819 if ((data
->mft_size
> MAX_MFT
) || (data
->idx_size
> MAX_IDX
))
822 data
->mmft
.data
= data
;
823 data
->cmft
.data
= data
;
825 data
->mmft
.buf
= grub_malloc (data
->mft_size
<< BLK_SHR
);
830 (disk
, data
->mft_start
, 0, data
->mft_size
<< BLK_SHR
, data
->mmft
.buf
))
833 data
->uuid
= grub_le_to_cpu64 (bpb
.num_serial
);
835 if (fixup (data
, data
->mmft
.buf
, data
->mft_size
, "FILE"))
838 if (!locate_attr (&data
->mmft
.attr
, &data
->mmft
, AT_DATA
))
841 if (init_file (&data
->cmft
, FILE_ROOT
))
847 grub_error (GRUB_ERR_BAD_FS
, "not an ntfs filesystem");
851 free_file (&data
->mmft
);
852 free_file (&data
->cmft
);
858 grub_ntfs_dir (grub_device_t device
, const char *path
,
859 int (*hook
) (const char *filename
, int dir
))
861 struct grub_ntfs_data
*data
= 0;
862 struct grub_fshelp_node
*fdiro
= 0;
864 auto int NESTED_FUNC_ATTR
iterate (const char *filename
,
865 enum grub_fshelp_filetype filetype
,
866 grub_fshelp_node_t node
);
868 int NESTED_FUNC_ATTR
iterate (const char *filename
,
869 enum grub_fshelp_filetype filetype
,
870 grub_fshelp_node_t node
)
874 if (filetype
== GRUB_FSHELP_DIR
)
875 return hook (filename
, 1);
877 return hook (filename
, 0);
883 grub_dl_ref (my_mod
);
887 data
= grub_ntfs_mount (device
->disk
);
891 grub_fshelp_find_file (path
, &data
->cmft
, &fdiro
, grub_ntfs_iterate_dir
,
897 grub_ntfs_iterate_dir (fdiro
, iterate
);
900 if ((fdiro
) && (fdiro
!= &data
->cmft
))
907 free_file (&data
->mmft
);
908 free_file (&data
->cmft
);
913 grub_dl_unref (my_mod
);
920 grub_ntfs_open (grub_file_t file
, const char *name
)
922 struct grub_ntfs_data
*data
= 0;
923 struct grub_fshelp_node
*mft
= 0;
926 grub_dl_ref (my_mod
);
929 data
= grub_ntfs_mount (file
->device
->disk
);
933 grub_fshelp_find_file (name
, &data
->cmft
, &mft
, grub_ntfs_iterate_dir
,
939 if (mft
!= &data
->cmft
)
941 free_file (&data
->cmft
);
942 grub_memcpy (&data
->cmft
, mft
, sizeof (*mft
));
944 if (!data
->cmft
.inode_read
)
946 if (init_file (&data
->cmft
, data
->cmft
.ino
))
951 file
->size
= data
->cmft
.size
;
960 free_file (&data
->mmft
);
961 free_file (&data
->cmft
);
966 grub_dl_unref (my_mod
);
973 grub_ntfs_read (grub_file_t file
, char *buf
, grub_size_t len
)
975 struct grub_ntfs_file
*mft
;
977 mft
= &((struct grub_ntfs_data
*) file
->data
)->cmft
;
979 mft
->attr
.save_pos
= 1;
981 if (file
->offset
> file
->size
)
983 grub_error (GRUB_ERR_BAD_FS
, "Bad offset");
987 if (file
->offset
+ len
> file
->size
)
988 len
= file
->size
- file
->offset
;
990 read_attr (&mft
->attr
, buf
, file
->offset
, len
, 1, file
->read_hook
);
991 return (grub_errno
) ? 0 : len
;
995 grub_ntfs_close (grub_file_t file
)
997 struct grub_ntfs_data
*data
;
1003 free_file (&data
->mmft
);
1004 free_file (&data
->cmft
);
1009 grub_dl_unref (my_mod
);
1016 grub_ntfs_label (grub_device_t device
, char **label
)
1018 struct grub_ntfs_data
*data
= 0;
1019 struct grub_fshelp_node
*mft
= 0;
1023 grub_dl_ref (my_mod
);
1028 data
= grub_ntfs_mount (device
->disk
);
1032 grub_fshelp_find_file ("/$Volume", &data
->cmft
, &mft
, grub_ntfs_iterate_dir
,
1033 0, GRUB_FSHELP_REG
);
1038 if (!mft
->inode_read
)
1040 mft
->buf
= grub_malloc (mft
->data
->mft_size
<< BLK_SHR
);
1041 if (mft
->buf
== NULL
)
1044 if (read_mft (mft
->data
, mft
->buf
, mft
->ino
))
1048 init_attr (&mft
->attr
, mft
);
1049 pa
= find_attr (&mft
->attr
, AT_VOLUME_NAME
);
1050 if ((pa
) && (pa
[8] == 0) && (u32at (pa
, 0x10)))
1055 len
= u32at (pa
, 0x10) / 2;
1056 buf
= grub_malloc (len
* 4 + 1);
1057 pa
+= u16at (pa
, 0x14);
1058 *grub_utf16_to_utf8 ((grub_uint8_t
*) buf
, (grub_uint16_t
*) pa
, len
) =
1064 if ((mft
) && (mft
!= &data
->cmft
))
1071 free_file (&data
->mmft
);
1072 free_file (&data
->cmft
);
1077 grub_dl_unref (my_mod
);
1084 grub_ntfs_uuid (grub_device_t device
, char **uuid
)
1086 struct grub_ntfs_data
*data
;
1087 grub_disk_t disk
= device
->disk
;
1090 grub_dl_ref (my_mod
);
1093 data
= grub_ntfs_mount (disk
);
1096 *uuid
= grub_malloc (16 + sizeof ('\0'));
1097 grub_sprintf (*uuid
, "%016llx", (unsigned long long) data
->uuid
);
1103 grub_dl_unref (my_mod
);
1111 static struct grub_fs grub_ntfs_fs
= {
1113 .dir
= grub_ntfs_dir
,
1114 .open
= grub_ntfs_open
,
1115 .read
= grub_ntfs_read
,
1116 .close
= grub_ntfs_close
,
1117 .label
= grub_ntfs_label
,
1118 .uuid
= grub_ntfs_uuid
,
1122 GRUB_MOD_INIT (ntfs
)
1124 grub_fs_register (&grub_ntfs_fs
);
1130 GRUB_MOD_FINI (ntfs
)
1132 grub_fs_unregister (&grub_ntfs_fs
);