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
))
578 char *ustr
, namespace;
580 if (pos
[0xC] & 2) /* end signature */
584 ns
= (unsigned char) *(np
++);
588 * Ignore files in DOS namespace, as they will reappear as Win32
591 if ((ns
) && (namespace != 2))
593 enum grub_fshelp_filetype type
;
594 struct grub_ntfs_file
*fdiro
;
598 grub_error (GRUB_ERR_BAD_FS
, "64-bit MFT number");
603 (u32at (pos
, 0x48) & ATTR_DIRECTORY
) ? GRUB_FSHELP_DIR
:
606 fdiro
= grub_malloc (sizeof (struct grub_ntfs_file
));
610 grub_memset (fdiro
, 0, sizeof (*fdiro
));
611 fdiro
->data
= diro
->data
;
612 fdiro
->ino
= u32at (pos
, 0);
614 ustr
= grub_malloc (ns
* 4 + 1);
617 *grub_utf16_to_utf8 ((grub_uint8_t
*) ustr
, (grub_uint16_t
*) np
,
621 type
|= GRUB_FSHELP_CASE_INSENSITIVE
;
623 if (hook (ustr
, type
, fdiro
))
631 pos
+= u16at (pos
, 8);
637 grub_ntfs_iterate_dir (grub_fshelp_node_t dir
,
639 (*hook
) (const char *filename
,
640 enum grub_fshelp_filetype filetype
,
641 grub_fshelp_node_t node
))
643 unsigned char *bitmap
;
644 struct grub_ntfs_attr attr
, *at
;
645 char *cur_pos
, *indx
, *bmp
;
646 int bitmap_len
, ret
= 0;
647 struct grub_ntfs_file
*mft
;
649 mft
= (struct grub_ntfs_file
*) dir
;
651 if (!mft
->inode_read
)
653 if (init_file (mft
, mft
->ino
))
664 if ((cur_pos
= find_attr (at
, AT_INDEX_ROOT
)) == NULL
)
666 grub_error (GRUB_ERR_BAD_FS
, "No $INDEX_ROOT");
670 /* Resident, Namelen=4, Offset=0x18, Flags=0x00, Name="$I30" */
671 if ((u32at (cur_pos
, 8) != 0x180400) ||
672 (u32at (cur_pos
, 0x18) != 0x490024) ||
673 (u32at (cur_pos
, 0x1C) != 0x300033))
675 cur_pos
+= u16at (cur_pos
, 0x14);
676 if (*cur_pos
!= 0x30) /* Not filename index */
681 cur_pos
+= 0x10; /* Skip index root */
682 ret
= list_file (mft
, cur_pos
+ u16at (cur_pos
, 0), hook
);
690 while ((cur_pos
= find_attr (at
, AT_BITMAP
)) != NULL
)
694 ofs
= (unsigned char) cur_pos
[0xA];
695 /* Namelen=4, Name="$I30" */
696 if ((cur_pos
[9] == 4) &&
697 (u32at (cur_pos
, ofs
) == 0x490024) &&
698 (u32at (cur_pos
, ofs
+ 4) == 0x300033))
700 int is_resident
= (cur_pos
[8] == 0);
702 bitmap_len
= ((is_resident
) ? u32at (cur_pos
, 0x10) :
703 u32at (cur_pos
, 0x28));
705 bmp
= grub_malloc (bitmap_len
);
711 grub_memcpy (bmp
, (char *) (cur_pos
+ u16at (cur_pos
, 0x14)),
716 if (read_data (at
, cur_pos
, bmp
, 0, bitmap_len
, 0, 0))
718 grub_error (GRUB_ERR_BAD_FS
,
719 "Fails to read non-resident $BITMAP");
722 bitmap_len
= u32at (cur_pos
, 0x30);
725 bitmap
= (unsigned char *) bmp
;
731 cur_pos
= locate_attr (at
, mft
, AT_INDEX_ALLOCATION
);
732 while (cur_pos
!= NULL
)
734 /* Non-resident, Namelen=4, Offset=0x40, Flags=0, Name="$I30" */
735 if ((u32at (cur_pos
, 8) == 0x400401) &&
736 (u32at (cur_pos
, 0x40) == 0x490024) &&
737 (u32at (cur_pos
, 0x44) == 0x300033))
739 cur_pos
= find_attr (at
, AT_INDEX_ALLOCATION
);
742 if ((!cur_pos
) && (bitmap
))
744 grub_error (GRUB_ERR_BAD_FS
, "$BITMAP without $INDEX_ALLOCATION");
752 indx
= grub_malloc (mft
->data
->idx_size
<< BLK_SHR
);
757 for (i
= 0; i
< (grub_uint32_t
) bitmap_len
* 8; i
++)
762 (at
, indx
, i
* (mft
->data
->idx_size
<< BLK_SHR
),
763 (mft
->data
->idx_size
<< BLK_SHR
), 0, 0))
764 || (fixup (mft
->data
, indx
, mft
->data
->idx_size
, "INDX")))
766 ret
= list_file (mft
, &indx
[0x18 + u16at (indx
, 0x18)], hook
);
787 static struct grub_ntfs_data
*
788 grub_ntfs_mount (grub_disk_t disk
)
790 struct grub_ntfs_bpb bpb
;
791 struct grub_ntfs_data
*data
= 0;
796 data
= (struct grub_ntfs_data
*) grub_malloc (sizeof (*data
));
800 grub_memset (data
, 0, sizeof (*data
));
805 if (grub_disk_read (disk
, 0, 0, sizeof (bpb
), (char *) &bpb
))
808 if (grub_memcmp ((char *) &bpb
.oem_name
, "NTFS", 4))
811 data
->blocksize
= grub_le_to_cpu16 (bpb
.bytes_per_sector
);
812 data
->spc
= bpb
.sectors_per_cluster
* (data
->blocksize
>> BLK_SHR
);
814 if (bpb
.clusters_per_mft
> 0)
815 data
->mft_size
= data
->spc
* bpb
.clusters_per_mft
;
817 data
->mft_size
= 1 << (-bpb
.clusters_per_mft
- BLK_SHR
);
819 if (bpb
.clusters_per_index
> 0)
820 data
->idx_size
= data
->spc
* bpb
.clusters_per_index
;
822 data
->idx_size
= 1 << (-bpb
.clusters_per_index
- BLK_SHR
);
824 data
->mft_start
= grub_le_to_cpu64 (bpb
.mft_lcn
) * data
->spc
;
826 if ((data
->mft_size
> MAX_MFT
) || (data
->idx_size
> MAX_IDX
))
829 data
->mmft
.data
= data
;
830 data
->cmft
.data
= data
;
832 data
->mmft
.buf
= grub_malloc (data
->mft_size
<< BLK_SHR
);
837 (disk
, data
->mft_start
, 0, data
->mft_size
<< BLK_SHR
, data
->mmft
.buf
))
840 data
->uuid
= grub_le_to_cpu64 (bpb
.num_serial
);
842 if (fixup (data
, data
->mmft
.buf
, data
->mft_size
, "FILE"))
845 if (!locate_attr (&data
->mmft
.attr
, &data
->mmft
, AT_DATA
))
848 if (init_file (&data
->cmft
, FILE_ROOT
))
854 grub_error (GRUB_ERR_BAD_FS
, "not an ntfs filesystem");
858 free_file (&data
->mmft
);
859 free_file (&data
->cmft
);
866 grub_ntfs_dir (grub_device_t device
, const char *path
,
867 int (*hook
) (const char *filename
,
868 const struct grub_dirhook_info
*info
))
870 struct grub_ntfs_data
*data
= 0;
871 struct grub_fshelp_node
*fdiro
= 0;
873 auto int NESTED_FUNC_ATTR
iterate (const char *filename
,
874 enum grub_fshelp_filetype filetype
,
875 grub_fshelp_node_t node
);
877 int NESTED_FUNC_ATTR
iterate (const char *filename
,
878 enum grub_fshelp_filetype filetype
,
879 grub_fshelp_node_t node
)
881 struct grub_dirhook_info info
;
882 grub_memset (&info
, 0, sizeof (info
));
883 info
.dir
= ((filetype
& GRUB_FSHELP_TYPE_MASK
) == GRUB_FSHELP_DIR
);
885 return hook (filename
, &info
);
889 grub_dl_ref (my_mod
);
893 data
= grub_ntfs_mount (device
->disk
);
897 grub_fshelp_find_file (path
, &data
->cmft
, &fdiro
, grub_ntfs_iterate_dir
,
903 grub_ntfs_iterate_dir (fdiro
, iterate
);
906 if ((fdiro
) && (fdiro
!= &data
->cmft
))
913 free_file (&data
->mmft
);
914 free_file (&data
->cmft
);
919 grub_dl_unref (my_mod
);
926 grub_ntfs_open (grub_file_t file
, const char *name
)
928 struct grub_ntfs_data
*data
= 0;
929 struct grub_fshelp_node
*mft
= 0;
932 grub_dl_ref (my_mod
);
935 data
= grub_ntfs_mount (file
->device
->disk
);
939 grub_fshelp_find_file (name
, &data
->cmft
, &mft
, grub_ntfs_iterate_dir
,
945 if (mft
!= &data
->cmft
)
947 free_file (&data
->cmft
);
948 grub_memcpy (&data
->cmft
, mft
, sizeof (*mft
));
950 if (!data
->cmft
.inode_read
)
952 if (init_file (&data
->cmft
, data
->cmft
.ino
))
957 file
->size
= data
->cmft
.size
;
966 free_file (&data
->mmft
);
967 free_file (&data
->cmft
);
972 grub_dl_unref (my_mod
);
979 grub_ntfs_read (grub_file_t file
, char *buf
, grub_size_t len
)
981 struct grub_ntfs_file
*mft
;
983 mft
= &((struct grub_ntfs_data
*) file
->data
)->cmft
;
985 mft
->attr
.save_pos
= 1;
987 if (file
->offset
> file
->size
)
989 grub_error (GRUB_ERR_BAD_FS
, "Bad offset");
993 if (file
->offset
+ len
> file
->size
)
994 len
= file
->size
- file
->offset
;
996 read_attr (&mft
->attr
, buf
, file
->offset
, len
, 1, file
->read_hook
);
997 return (grub_errno
) ? 0 : len
;
1001 grub_ntfs_close (grub_file_t file
)
1003 struct grub_ntfs_data
*data
;
1009 free_file (&data
->mmft
);
1010 free_file (&data
->cmft
);
1015 grub_dl_unref (my_mod
);
1022 grub_ntfs_label (grub_device_t device
, char **label
)
1024 struct grub_ntfs_data
*data
= 0;
1025 struct grub_fshelp_node
*mft
= 0;
1029 grub_dl_ref (my_mod
);
1034 data
= grub_ntfs_mount (device
->disk
);
1038 grub_fshelp_find_file ("/$Volume", &data
->cmft
, &mft
, grub_ntfs_iterate_dir
,
1039 0, GRUB_FSHELP_REG
);
1044 if (!mft
->inode_read
)
1046 mft
->buf
= grub_malloc (mft
->data
->mft_size
<< BLK_SHR
);
1047 if (mft
->buf
== NULL
)
1050 if (read_mft (mft
->data
, mft
->buf
, mft
->ino
))
1054 init_attr (&mft
->attr
, mft
);
1055 pa
= find_attr (&mft
->attr
, AT_VOLUME_NAME
);
1056 if ((pa
) && (pa
[8] == 0) && (u32at (pa
, 0x10)))
1061 len
= u32at (pa
, 0x10) / 2;
1062 buf
= grub_malloc (len
* 4 + 1);
1063 pa
+= u16at (pa
, 0x14);
1064 *grub_utf16_to_utf8 ((grub_uint8_t
*) buf
, (grub_uint16_t
*) pa
, len
) =
1070 if ((mft
) && (mft
!= &data
->cmft
))
1077 free_file (&data
->mmft
);
1078 free_file (&data
->cmft
);
1083 grub_dl_unref (my_mod
);
1090 grub_ntfs_uuid (grub_device_t device
, char **uuid
)
1092 struct grub_ntfs_data
*data
;
1093 grub_disk_t disk
= device
->disk
;
1096 grub_dl_ref (my_mod
);
1099 data
= grub_ntfs_mount (disk
);
1102 *uuid
= grub_malloc (16 + sizeof ('\0'));
1103 grub_sprintf (*uuid
, "%016llx", (unsigned long long) data
->uuid
);
1109 grub_dl_unref (my_mod
);
1117 static struct grub_fs grub_ntfs_fs
= {
1119 .dir
= grub_ntfs_dir
,
1120 .open
= grub_ntfs_open
,
1121 .read
= grub_ntfs_read
,
1122 .close
= grub_ntfs_close
,
1123 .label
= grub_ntfs_label
,
1124 .uuid
= grub_ntfs_uuid
,
1128 GRUB_MOD_INIT (ntfs
)
1130 grub_fs_register (&grub_ntfs_fs
);
1136 GRUB_MOD_FINI (ntfs
)
1138 grub_fs_unregister (&grub_ntfs_fs
);