Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
dadigang
Ventoy
Commits
84c50066
Commit
84c50066
authored
May 16, 2020
by
longpanda
Browse files
1.0.10 release
parent
fe0dda69
Changes
27
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
4657 additions
and
125 deletions
+4657
-125
GRUB2/grub-2.04/grub-core/disk/i386/pc/biosdisk.c
GRUB2/grub-2.04/grub-core/disk/i386/pc/biosdisk.c
+1
-1
GRUB2/grub-2.04/grub-core/fs/ext2.c
GRUB2/grub-2.04/grub-core/fs/ext2.c
+1100
-0
GRUB2/grub-2.04/grub-core/fs/fat.c
GRUB2/grub-2.04/grub-core/fs/fat.c
+1
-51
GRUB2/grub-2.04/grub-core/fs/ntfs.c
GRUB2/grub-2.04/grub-core/fs/ntfs.c
+1239
-0
GRUB2/grub-2.04/grub-core/fs/udf.c
GRUB2/grub-2.04/grub-core/fs/udf.c
+2
-0
GRUB2/grub-2.04/grub-core/fs/xfs.c
GRUB2/grub-2.04/grub-core/fs/xfs.c
+1164
-0
GRUB2/grub-2.04/grub-core/kern/disk.c
GRUB2/grub-2.04/grub-core/kern/disk.c
+600
-0
GRUB2/grub-2.04/grub-core/ventoy/ventoy.c
GRUB2/grub-2.04/grub-core/ventoy/ventoy.c
+203
-16
GRUB2/grub-2.04/grub-core/ventoy/ventoy_def.h
GRUB2/grub-2.04/grub-core/ventoy/ventoy_def.h
+2
-0
GRUB2/grub-2.04/grub-core/ventoy/ventoy_windows.c
GRUB2/grub-2.04/grub-core/ventoy/ventoy_windows.c
+2
-3
GRUB2/grub-2.04/include/grub/disk.h
GRUB2/grub-2.04/include/grub/disk.h
+265
-0
GRUB2/grub-2.04/include/grub/ventoy.h
GRUB2/grub-2.04/include/grub/ventoy.h
+11
-0
INSTALL/EFI/BOOT/grubx64_real.efi
INSTALL/EFI/BOOT/grubx64_real.efi
+0
-0
INSTALL/Ventoy2Disk.exe
INSTALL/Ventoy2Disk.exe
+0
-0
INSTALL/Ventoy2Disk.sh
INSTALL/Ventoy2Disk.sh
+28
-23
INSTALL/grub/grub.cfg
INSTALL/grub/grub.cfg
+33
-15
INSTALL/grub/i386-pc/core.img
INSTALL/grub/i386-pc/core.img
+0
-0
INSTALL/tool/ventoy_lib.sh
INSTALL/tool/ventoy_lib.sh
+6
-16
INSTALL/ventoy/ipxe.krn
INSTALL/ventoy/ipxe.krn
+0
-0
INSTALL/ventoy/ventoy.cpio
INSTALL/ventoy/ventoy.cpio
+0
-0
No files found.
GRUB2/grub-2.04/grub-core/disk/i386/pc/biosdisk.c
View file @
84c50066
...
...
@@ -374,7 +374,7 @@ static int ventoy_is_mbr_match(ventoy_mbr_head *head)
return
0
;
}
if
(
head
->
PartTbl
[
0
].
FsFlag
!=
0x07
||
head
->
PartTbl
[
0
].
StartSectorId
!=
2048
)
{
if
(
head
->
PartTbl
[
0
].
StartSectorId
!=
2048
)
{
return
0
;
}
...
...
GRUB2/grub-2.04/grub-core/fs/ext2.c
0 → 100644
View file @
84c50066
/* ext2.c - Second Extended filesystem */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2003,2004,2005,2007,2008,2009 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
/* Magic value used to identify an ext2 filesystem. */
#define EXT2_MAGIC 0xEF53
/* Amount of indirect blocks in an inode. */
#define INDIRECT_BLOCKS 12
/* The good old revision and the default inode size. */
#define EXT2_GOOD_OLD_REVISION 0
#define EXT2_GOOD_OLD_INODE_SIZE 128
/* Filetype used in directory entry. */
#define FILETYPE_UNKNOWN 0
#define FILETYPE_REG 1
#define FILETYPE_DIRECTORY 2
#define FILETYPE_SYMLINK 7
/* Filetype information as used in inodes. */
#define FILETYPE_INO_MASK 0170000
#define FILETYPE_INO_REG 0100000
#define FILETYPE_INO_DIRECTORY 0040000
#define FILETYPE_INO_SYMLINK 0120000
#include <grub/err.h>
#include <grub/file.h>
#include <grub/mm.h>
#include <grub/misc.h>
#include <grub/disk.h>
#include <grub/dl.h>
#include <grub/types.h>
#include <grub/fshelp.h>
GRUB_MOD_LICENSE
(
"GPLv3+"
);
/* Log2 size of ext2 block in 512 blocks. */
#define LOG2_EXT2_BLOCK_SIZE(data) \
(grub_le_to_cpu32 (data->sblock.log2_block_size) + 1)
/* Log2 size of ext2 block in bytes. */
#define LOG2_BLOCK_SIZE(data) \
(grub_le_to_cpu32 (data->sblock.log2_block_size) + 10)
/* The size of an ext2 block in bytes. */
#define EXT2_BLOCK_SIZE(data) (1U << LOG2_BLOCK_SIZE (data))
/* The revision level. */
#define EXT2_REVISION(data) grub_le_to_cpu32 (data->sblock.revision_level)
/* The inode size. */
#define EXT2_INODE_SIZE(data) \
(data->sblock.revision_level \
== grub_cpu_to_le32_compile_time (EXT2_GOOD_OLD_REVISION) \
? EXT2_GOOD_OLD_INODE_SIZE \
: grub_le_to_cpu16 (data->sblock.inode_size))
/* Superblock filesystem feature flags (RW compatible)
* A filesystem with any of these enabled can be read and written by a driver
* that does not understand them without causing metadata/data corruption. */
#define EXT2_FEATURE_COMPAT_DIR_PREALLOC 0x0001
#define EXT2_FEATURE_COMPAT_IMAGIC_INODES 0x0002
#define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x0004
#define EXT2_FEATURE_COMPAT_EXT_ATTR 0x0008
#define EXT2_FEATURE_COMPAT_RESIZE_INODE 0x0010
#define EXT2_FEATURE_COMPAT_DIR_INDEX 0x0020
/* Superblock filesystem feature flags (RO compatible)
* A filesystem with any of these enabled can be safely read by a driver that
* does not understand them, but should not be written to, usually because
* additional metadata is required. */
#define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001
#define EXT2_FEATURE_RO_COMPAT_LARGE_FILE 0x0002
#define EXT2_FEATURE_RO_COMPAT_BTREE_DIR 0x0004
#define EXT4_FEATURE_RO_COMPAT_GDT_CSUM 0x0010
#define EXT4_FEATURE_RO_COMPAT_DIR_NLINK 0x0020
#define EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE 0x0040
/* Superblock filesystem feature flags (back-incompatible)
* A filesystem with any of these enabled should not be attempted to be read
* by a driver that does not understand them, since they usually indicate
* metadata format changes that might confuse the reader. */
#define EXT2_FEATURE_INCOMPAT_COMPRESSION 0x0001
#define EXT2_FEATURE_INCOMPAT_FILETYPE 0x0002
#define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004
/* Needs recovery */
#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008
/* Volume is journal device */
#define EXT2_FEATURE_INCOMPAT_META_BG 0x0010
#define EXT4_FEATURE_INCOMPAT_EXTENTS 0x0040
/* Extents used */
#define EXT4_FEATURE_INCOMPAT_64BIT 0x0080
#define EXT4_FEATURE_INCOMPAT_MMP 0x0100
#define EXT4_FEATURE_INCOMPAT_FLEX_BG 0x0200
#define EXT4_FEATURE_INCOMPAT_ENCRYPT 0x10000
/* The set of back-incompatible features this driver DOES support. Add (OR)
* flags here as the related features are implemented into the driver. */
#define EXT2_DRIVER_SUPPORTED_INCOMPAT ( EXT2_FEATURE_INCOMPAT_FILETYPE \
| EXT4_FEATURE_INCOMPAT_EXTENTS \
| EXT4_FEATURE_INCOMPAT_FLEX_BG \
| EXT2_FEATURE_INCOMPAT_META_BG \
| EXT4_FEATURE_INCOMPAT_64BIT \
| EXT4_FEATURE_INCOMPAT_ENCRYPT)
/* List of rationales for the ignored "incompatible" features:
* needs_recovery: Not really back-incompatible - was added as such to forbid
* ext2 drivers from mounting an ext3 volume with a dirty
* journal because they will ignore the journal, but the next
* ext3 driver to mount the volume will find the journal and
* replay it, potentially corrupting the metadata written by
* the ext2 drivers. Safe to ignore for this RO driver.
* mmp: Not really back-incompatible - was added as such to
* avoid multiple read-write mounts. Safe to ignore for this
* RO driver.
*/
#define EXT2_DRIVER_IGNORED_INCOMPAT ( EXT3_FEATURE_INCOMPAT_RECOVER \
| EXT4_FEATURE_INCOMPAT_MMP)
#define EXT3_JOURNAL_MAGIC_NUMBER 0xc03b3998U
#define EXT3_JOURNAL_DESCRIPTOR_BLOCK 1
#define EXT3_JOURNAL_COMMIT_BLOCK 2
#define EXT3_JOURNAL_SUPERBLOCK_V1 3
#define EXT3_JOURNAL_SUPERBLOCK_V2 4
#define EXT3_JOURNAL_REVOKE_BLOCK 5
#define EXT3_JOURNAL_FLAG_ESCAPE 1
#define EXT3_JOURNAL_FLAG_SAME_UUID 2
#define EXT3_JOURNAL_FLAG_DELETED 4
#define EXT3_JOURNAL_FLAG_LAST_TAG 8
#define EXT4_ENCRYPT_FLAG 0x800
#define EXT4_EXTENTS_FLAG 0x80000
/* The ext2 superblock. */
struct
grub_ext2_sblock
{
grub_uint32_t
total_inodes
;
grub_uint32_t
total_blocks
;
grub_uint32_t
reserved_blocks
;
grub_uint32_t
free_blocks
;
grub_uint32_t
free_inodes
;
grub_uint32_t
first_data_block
;
grub_uint32_t
log2_block_size
;
grub_uint32_t
log2_fragment_size
;
grub_uint32_t
blocks_per_group
;
grub_uint32_t
fragments_per_group
;
grub_uint32_t
inodes_per_group
;
grub_uint32_t
mtime
;
grub_uint32_t
utime
;
grub_uint16_t
mnt_count
;
grub_uint16_t
max_mnt_count
;
grub_uint16_t
magic
;
grub_uint16_t
fs_state
;
grub_uint16_t
error_handling
;
grub_uint16_t
minor_revision_level
;
grub_uint32_t
lastcheck
;
grub_uint32_t
checkinterval
;
grub_uint32_t
creator_os
;
grub_uint32_t
revision_level
;
grub_uint16_t
uid_reserved
;
grub_uint16_t
gid_reserved
;
grub_uint32_t
first_inode
;
grub_uint16_t
inode_size
;
grub_uint16_t
block_group_number
;
grub_uint32_t
feature_compatibility
;
grub_uint32_t
feature_incompat
;
grub_uint32_t
feature_ro_compat
;
grub_uint16_t
uuid
[
8
];
char
volume_name
[
16
];
char
last_mounted_on
[
64
];
grub_uint32_t
compression_info
;
grub_uint8_t
prealloc_blocks
;
grub_uint8_t
prealloc_dir_blocks
;
grub_uint16_t
reserved_gdt_blocks
;
grub_uint8_t
journal_uuid
[
16
];
grub_uint32_t
journal_inum
;
grub_uint32_t
journal_dev
;
grub_uint32_t
last_orphan
;
grub_uint32_t
hash_seed
[
4
];
grub_uint8_t
def_hash_version
;
grub_uint8_t
jnl_backup_type
;
grub_uint16_t
group_desc_size
;
grub_uint32_t
default_mount_opts
;
grub_uint32_t
first_meta_bg
;
grub_uint32_t
mkfs_time
;
grub_uint32_t
jnl_blocks
[
17
];
};
/* The ext2 blockgroup. */
struct
grub_ext2_block_group
{
grub_uint32_t
block_id
;
grub_uint32_t
inode_id
;
grub_uint32_t
inode_table_id
;
grub_uint16_t
free_blocks
;
grub_uint16_t
free_inodes
;
grub_uint16_t
used_dirs
;
grub_uint16_t
pad
;
grub_uint32_t
reserved
[
3
];
grub_uint32_t
block_id_hi
;
grub_uint32_t
inode_id_hi
;
grub_uint32_t
inode_table_id_hi
;
grub_uint16_t
free_blocks_hi
;
grub_uint16_t
free_inodes_hi
;
grub_uint16_t
used_dirs_hi
;
grub_uint16_t
pad2
;
grub_uint32_t
reserved2
[
3
];
};
/* The ext2 inode. */
struct
grub_ext2_inode
{
grub_uint16_t
mode
;
grub_uint16_t
uid
;
grub_uint32_t
size
;
grub_uint32_t
atime
;
grub_uint32_t
ctime
;
grub_uint32_t
mtime
;
grub_uint32_t
dtime
;
grub_uint16_t
gid
;
grub_uint16_t
nlinks
;
grub_uint32_t
blockcnt
;
/* Blocks of 512 bytes!! */
grub_uint32_t
flags
;
grub_uint32_t
osd1
;
union
{
struct
datablocks
{
grub_uint32_t
dir_blocks
[
INDIRECT_BLOCKS
];
grub_uint32_t
indir_block
;
grub_uint32_t
double_indir_block
;
grub_uint32_t
triple_indir_block
;
}
blocks
;
char
symlink
[
60
];
};
grub_uint32_t
version
;
grub_uint32_t
acl
;
grub_uint32_t
size_high
;
grub_uint32_t
fragment_addr
;
grub_uint32_t
osd2
[
3
];
};
/* The header of an ext2 directory entry. */
struct
ext2_dirent
{
grub_uint32_t
inode
;
grub_uint16_t
direntlen
;
#define MAX_NAMELEN 255
grub_uint8_t
namelen
;
grub_uint8_t
filetype
;
};
struct
grub_ext3_journal_header
{
grub_uint32_t
magic
;
grub_uint32_t
block_type
;
grub_uint32_t
sequence
;
};
struct
grub_ext3_journal_revoke_header
{
struct
grub_ext3_journal_header
header
;
grub_uint32_t
count
;
grub_uint32_t
data
[
0
];
};
struct
grub_ext3_journal_block_tag
{
grub_uint32_t
block
;
grub_uint32_t
flags
;
};
struct
grub_ext3_journal_sblock
{
struct
grub_ext3_journal_header
header
;
grub_uint32_t
block_size
;
grub_uint32_t
maxlen
;
grub_uint32_t
first
;
grub_uint32_t
sequence
;
grub_uint32_t
start
;
};
#define EXT4_EXT_MAGIC 0xf30a
struct
grub_ext4_extent_header
{
grub_uint16_t
magic
;
grub_uint16_t
entries
;
grub_uint16_t
max
;
grub_uint16_t
depth
;
grub_uint32_t
generation
;
};
struct
grub_ext4_extent
{
grub_uint32_t
block
;
grub_uint16_t
len
;
grub_uint16_t
start_hi
;
grub_uint32_t
start
;
};
struct
grub_ext4_extent_idx
{
grub_uint32_t
block
;
grub_uint32_t
leaf
;
grub_uint16_t
leaf_hi
;
grub_uint16_t
unused
;
};
struct
grub_fshelp_node
{
struct
grub_ext2_data
*
data
;
struct
grub_ext2_inode
inode
;
int
ino
;
int
inode_read
;
};
/* Information about a "mounted" ext2 filesystem. */
struct
grub_ext2_data
{
struct
grub_ext2_sblock
sblock
;
int
log_group_desc_size
;
grub_disk_t
disk
;
struct
grub_ext2_inode
*
inode
;
struct
grub_fshelp_node
diropen
;
};
static
grub_dl_t
my_mod
;
/* Check is a = b^x for some x. */
static
inline
int
is_power_of
(
grub_uint64_t
a
,
grub_uint32_t
b
)
{
grub_uint64_t
c
;
/* Prevent overflow assuming b < 8. */
if
(
a
>=
(
1LL
<<
60
))
return
0
;
for
(
c
=
1
;
c
<=
a
;
c
*=
b
);
return
(
c
==
a
);
}
static
inline
int
group_has_super_block
(
struct
grub_ext2_data
*
data
,
grub_uint64_t
group
)
{
if
(
!
(
data
->
sblock
.
feature_ro_compat
&
grub_cpu_to_le32_compile_time
(
EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER
)))
return
1
;
/* Algorithm looked up in Linux source. */
if
(
group
<=
1
)
return
1
;
/* Even number is never a power of odd number. */
if
(
!
(
group
&
1
))
return
0
;
return
(
is_power_of
(
group
,
7
)
||
is_power_of
(
group
,
5
)
||
is_power_of
(
group
,
3
));
}
/* Read into BLKGRP the blockgroup descriptor of blockgroup GROUP of
the mounted filesystem DATA. */
inline
static
grub_err_t
grub_ext2_blockgroup
(
struct
grub_ext2_data
*
data
,
grub_uint64_t
group
,
struct
grub_ext2_block_group
*
blkgrp
)
{
grub_uint64_t
full_offset
=
(
group
<<
data
->
log_group_desc_size
);
grub_uint64_t
block
,
offset
;
block
=
(
full_offset
>>
LOG2_BLOCK_SIZE
(
data
));
offset
=
(
full_offset
&
((
1
<<
LOG2_BLOCK_SIZE
(
data
))
-
1
));
if
((
data
->
sblock
.
feature_incompat
&
grub_cpu_to_le32_compile_time
(
EXT2_FEATURE_INCOMPAT_META_BG
))
&&
block
>=
grub_le_to_cpu32
(
data
->
sblock
.
first_meta_bg
))
{
grub_uint64_t
first_block_group
;
/* Find the first block group for which a descriptor
is stored in given block. */
first_block_group
=
(
block
<<
(
LOG2_BLOCK_SIZE
(
data
)
-
data
->
log_group_desc_size
));
block
=
(
first_block_group
*
grub_le_to_cpu32
(
data
->
sblock
.
blocks_per_group
));
if
(
group_has_super_block
(
data
,
first_block_group
))
block
++
;
}
else
/* Superblock. */
block
++
;
return
grub_disk_read
(
data
->
disk
,
((
grub_le_to_cpu32
(
data
->
sblock
.
first_data_block
)
+
block
)
<<
LOG2_EXT2_BLOCK_SIZE
(
data
)),
offset
,
sizeof
(
struct
grub_ext2_block_group
),
blkgrp
);
}
static
struct
grub_ext4_extent_header
*
grub_ext4_find_leaf
(
struct
grub_ext2_data
*
data
,
struct
grub_ext4_extent_header
*
ext_block
,
grub_uint32_t
fileblock
)
{
struct
grub_ext4_extent_idx
*
index
;
void
*
buf
=
NULL
;
while
(
1
)
{
int
i
;
grub_disk_addr_t
block
;
index
=
(
struct
grub_ext4_extent_idx
*
)
(
ext_block
+
1
);
if
(
ext_block
->
magic
!=
grub_cpu_to_le16_compile_time
(
EXT4_EXT_MAGIC
))
goto
fail
;
if
(
ext_block
->
depth
==
0
)
return
ext_block
;
for
(
i
=
0
;
i
<
grub_le_to_cpu16
(
ext_block
->
entries
);
i
++
)
{
if
(
fileblock
<
grub_le_to_cpu32
(
index
[
i
].
block
))
break
;
}
if
(
--
i
<
0
)
goto
fail
;
block
=
grub_le_to_cpu16
(
index
[
i
].
leaf_hi
);
block
=
(
block
<<
32
)
|
grub_le_to_cpu32
(
index
[
i
].
leaf
);
if
(
!
buf
)
buf
=
grub_malloc
(
EXT2_BLOCK_SIZE
(
data
));
if
(
!
buf
)
goto
fail
;
if
(
grub_disk_read
(
data
->
disk
,
block
<<
LOG2_EXT2_BLOCK_SIZE
(
data
),
0
,
EXT2_BLOCK_SIZE
(
data
),
buf
))
goto
fail
;
ext_block
=
buf
;
}
fail:
grub_free
(
buf
);
return
0
;
}
static
grub_disk_addr_t
grub_ext2_read_block
(
grub_fshelp_node_t
node
,
grub_disk_addr_t
fileblock
)
{
struct
grub_ext2_data
*
data
=
node
->
data
;
struct
grub_ext2_inode
*
inode
=
&
node
->
inode
;
unsigned
int
blksz
=
EXT2_BLOCK_SIZE
(
data
);
grub_disk_addr_t
blksz_quarter
=
blksz
/
4
;
int
log2_blksz
=
LOG2_EXT2_BLOCK_SIZE
(
data
);
int
log_perblock
=
log2_blksz
+
9
-
2
;
grub_uint32_t
indir
;
int
shift
;
if
(
inode
->
flags
&
grub_cpu_to_le32_compile_time
(
EXT4_EXTENTS_FLAG
))
{
struct
grub_ext4_extent_header
*
leaf
;
struct
grub_ext4_extent
*
ext
;
int
i
;
grub_disk_addr_t
ret
;
leaf
=
grub_ext4_find_leaf
(
data
,
(
struct
grub_ext4_extent_header
*
)
inode
->
blocks
.
dir_blocks
,
fileblock
);
if
(
!
leaf
)
{
grub_error
(
GRUB_ERR_BAD_FS
,
"invalid extent"
);
return
-
1
;
}
ext
=
(
struct
grub_ext4_extent
*
)
(
leaf
+
1
);
for
(
i
=
0
;
i
<
grub_le_to_cpu16
(
leaf
->
entries
);
i
++
)
{
if
(
fileblock
<
grub_le_to_cpu32
(
ext
[
i
].
block
))
break
;
}
if
(
--
i
>=
0
)
{
fileblock
-=
grub_le_to_cpu32
(
ext
[
i
].
block
);
if
(
fileblock
>=
grub_le_to_cpu16
(
ext
[
i
].
len
))
ret
=
0
;
else
{
grub_disk_addr_t
start
;
start
=
grub_le_to_cpu16
(
ext
[
i
].
start_hi
);
start
=
(
start
<<
32
)
+
grub_le_to_cpu32
(
ext
[
i
].
start
);
ret
=
fileblock
+
start
;
}
}
else
{
grub_error
(
GRUB_ERR_BAD_FS
,
"something wrong with extent"
);
ret
=
-
1
;
}
if
(
leaf
!=
(
struct
grub_ext4_extent_header
*
)
inode
->
blocks
.
dir_blocks
)
grub_free
(
leaf
);
return
ret
;
}
/* Direct blocks. */
if
(
fileblock
<
INDIRECT_BLOCKS
)
return
grub_le_to_cpu32
(
inode
->
blocks
.
dir_blocks
[
fileblock
]);
fileblock
-=
INDIRECT_BLOCKS
;
/* Indirect. */
if
(
fileblock
<
blksz_quarter
)
{
indir
=
inode
->
blocks
.
indir_block
;
shift
=
0
;
goto
indirect
;
}
fileblock
-=
blksz_quarter
;
/* Double indirect. */
if
(
fileblock
<
blksz_quarter
*
blksz_quarter
)
{
indir
=
inode
->
blocks
.
double_indir_block
;
shift
=
1
;
goto
indirect
;
}
fileblock
-=
blksz_quarter
*
blksz_quarter
;
/* Triple indirect. */
if
(
fileblock
<
blksz_quarter
*
blksz_quarter
*
(
blksz_quarter
+
1
))
{
indir
=
inode
->
blocks
.
triple_indir_block
;
shift
=
2
;
goto
indirect
;
}
grub_error
(
GRUB_ERR_BAD_FS
,
"ext2fs doesn't support quadruple indirect blocks"
);
return
-
1
;
indirect:
do
{
/* If the indirect block is zero, all child blocks are absent
(i.e. filled with zeros.) */
if
(
indir
==
0
)
return
0
;
if
(
grub_disk_read
(
data
->
disk
,
((
grub_disk_addr_t
)
grub_le_to_cpu32
(
indir
))
<<
log2_blksz
,
((
fileblock
>>
(
log_perblock
*
shift
))
&
((
1
<<
log_perblock
)
-
1
))
*
sizeof
(
indir
),
sizeof
(
indir
),
&
indir
))
return
-
1
;
}
while
(
shift
--
);
return
grub_le_to_cpu32
(
indir
);
}
/* Read LEN bytes from the file described by DATA starting with byte
POS. Return the amount of read bytes in READ. */
static
grub_ssize_t
grub_ext2_read_file
(
grub_fshelp_node_t
node
,
grub_disk_read_hook_t
read_hook
,
void
*
read_hook_data
,
grub_off_t
pos
,
grub_size_t
len
,
char
*
buf
)
{
return
grub_fshelp_read_file
(
node
->
data
->
disk
,
node
,
read_hook
,
read_hook_data
,
pos
,
len
,
buf
,
grub_ext2_read_block
,
grub_cpu_to_le32
(
node
->
inode
.
size
)
|
(((
grub_off_t
)
grub_cpu_to_le32
(
node
->
inode
.
size_high
))
<<
32
),
LOG2_EXT2_BLOCK_SIZE
(
node
->
data
),
0
);
}
/* Read the inode INO for the file described by DATA into INODE. */
static
grub_err_t
grub_ext2_read_inode
(
struct
grub_ext2_data
*
data
,
int
ino
,
struct
grub_ext2_inode
*
inode
)
{
struct
grub_ext2_block_group
blkgrp
;
struct
grub_ext2_sblock
*
sblock
=
&
data
->
sblock
;
int
inodes_per_block
;
unsigned
int
blkno
;
unsigned
int
blkoff
;
grub_disk_addr_t
base
;
/* It is easier to calculate if the first inode is 0. */
ino
--
;
grub_ext2_blockgroup
(
data
,
ino
/
grub_le_to_cpu32
(
sblock
->
inodes_per_group
),
&
blkgrp
);
if
(
grub_errno
)
return
grub_errno
;
inodes_per_block
=
EXT2_BLOCK_SIZE
(
data
)
/
EXT2_INODE_SIZE
(
data
);
blkno
=
(
ino
%
grub_le_to_cpu32
(
sblock
->
inodes_per_group
))
/
inodes_per_block
;
blkoff
=
(
ino
%
grub_le_to_cpu32
(
sblock
->
inodes_per_group
))
%
inodes_per_block
;
base
=
grub_le_to_cpu32
(
blkgrp
.
inode_table_id
);
if
(
data
->
log_group_desc_size
>=
6
)
base
|=
(((
grub_disk_addr_t
)
grub_le_to_cpu32
(
blkgrp
.
inode_table_id_hi
))
<<
32
);
/* Read the inode. */
if
(
grub_disk_read
(
data
->
disk
,
((
base
+
blkno
)
<<
LOG2_EXT2_BLOCK_SIZE
(
data
)),
EXT2_INODE_SIZE
(
data
)
*
blkoff
,
sizeof
(
struct
grub_ext2_inode
),
inode
))
return
grub_errno
;
return
0
;
}
static
struct
grub_ext2_data
*
grub_ext2_mount
(
grub_disk_t
disk
)
{
struct
grub_ext2_data
*
data
;
data
=
grub_malloc
(
sizeof
(
struct
grub_ext2_data
));
if
(
!
data
)
return
0
;
/* Read the superblock. */
grub_disk_read
(
disk
,
1
*
2
,
0
,
sizeof
(
struct
grub_ext2_sblock
),
&
data
->
sblock
);
if
(
grub_errno
)
goto
fail
;
/* Make sure this is an ext2 filesystem. */
if
(
data
->
sblock
.
magic
!=
grub_cpu_to_le16_compile_time
(
EXT2_MAGIC
)
||
grub_le_to_cpu32
(
data
->
sblock
.
log2_block_size
)
>=
16
||
data
->
sblock
.
inodes_per_group
==
0
/* 20 already means 1GiB blocks. We don't want to deal with blocks overflowing int32. */
||
grub_le_to_cpu32
(
data
->
sblock
.
log2_block_size
)
>
20
||
EXT2_INODE_SIZE
(
data
)
==
0
||
EXT2_BLOCK_SIZE
(
data
)
/
EXT2_INODE_SIZE
(
data
)
==
0
)
{
grub_error
(
GRUB_ERR_BAD_FS
,
"not an ext2 filesystem"
);
goto
fail
;
}
/* Check the FS doesn't have feature bits enabled that we don't support. */
if
(
data
->
sblock
.
revision_level
!=
grub_cpu_to_le32_compile_time
(
EXT2_GOOD_OLD_REVISION
)
&&
(
data
->
sblock
.
feature_incompat
&
grub_cpu_to_le32_compile_time
(
~
(
EXT2_DRIVER_SUPPORTED_INCOMPAT
|
EXT2_DRIVER_IGNORED_INCOMPAT
))))
{
grub_error
(
GRUB_ERR_BAD_FS
,
"filesystem has unsupported incompatible features"
);
goto
fail
;
}
if
(
data
->
sblock
.
revision_level
!=
grub_cpu_to_le32_compile_time
(
EXT2_GOOD_OLD_REVISION
)
&&
(
data
->
sblock
.
feature_incompat
&
grub_cpu_to_le32_compile_time
(
EXT4_FEATURE_INCOMPAT_64BIT
))
&&
data
->
sblock
.
group_desc_size
!=
0
&&
((
data
->
sblock
.
group_desc_size
&
(
data
->
sblock
.
group_desc_size
-
1
))
==
0
)
&&
(
data
->
sblock
.
group_desc_size
&
grub_cpu_to_le16_compile_time
(
0x1fe0
)))
{
grub_uint16_t
b
=
grub_le_to_cpu16
(
data
->
sblock
.
group_desc_size
);
for
(
data
->
log_group_desc_size
=
0
;
b
!=
(
1
<<
data
->
log_group_desc_size
);
data
->
log_group_desc_size
++
);
}
else
data
->
log_group_desc_size
=
5
;
data
->
disk
=
disk
;
data
->
diropen
.
data
=
data
;
data
->
diropen
.
ino
=
2
;
data
->
diropen
.
inode_read
=
1
;
data
->
inode
=
&
data
->
diropen
.
inode
;
grub_ext2_read_inode
(
data
,
2
,
data
->
inode
);
if
(
grub_errno
)
goto
fail
;
return
data
;
fail:
if
(
grub_errno
==
GRUB_ERR_OUT_OF_RANGE
)
grub_error
(
GRUB_ERR_BAD_FS
,
"not an ext2 filesystem"
);
grub_free
(
data
);
return
0
;
}
static
char
*
grub_ext2_read_symlink
(
grub_fshelp_node_t
node
)
{
char
*
symlink
;
struct
grub_fshelp_node
*
diro
=
node
;
if
(
!
diro
->
inode_read
)
{
grub_ext2_read_inode
(
diro
->
data
,
diro
->
ino
,
&
diro
->
inode
);
if
(
grub_errno
)
return
0
;
if
(
diro
->
inode
.
flags
&
grub_cpu_to_le32_compile_time
(
EXT4_ENCRYPT_FLAG
))
{
grub_error
(
GRUB_ERR_NOT_IMPLEMENTED_YET
,
"symlink is encrypted"
);
return
0
;
}
}
symlink
=
grub_malloc
(
grub_le_to_cpu32
(
diro
->
inode
.
size
)
+
1
);
if
(
!
symlink
)
return
0
;
/* If the filesize of the symlink is bigger than
60 the symlink is stored in a separate block,
otherwise it is stored in the inode. */
if
(
grub_le_to_cpu32
(
diro
->
inode
.
size
)
<=
sizeof
(
diro
->
inode
.
symlink
))
grub_memcpy
(
symlink
,
diro
->
inode
.
symlink
,
grub_le_to_cpu32
(
diro
->
inode
.
size
));
else
{
grub_ext2_read_file
(
diro
,
0
,
0
,
0
,
grub_le_to_cpu32
(
diro
->
inode
.
size
),
symlink
);
if
(
grub_errno
)
{
grub_free
(
symlink
);
return
0
;
}
}
symlink
[
grub_le_to_cpu32
(
diro
->
inode
.
size
)]
=
'\0'
;
return
symlink
;
}
static
int
grub_ext2_iterate_dir
(
grub_fshelp_node_t
dir
,
grub_fshelp_iterate_dir_hook_t
hook
,
void
*
hook_data
)
{
unsigned
int
fpos
=
0
;
struct
grub_fshelp_node
*
diro
=
(
struct
grub_fshelp_node
*
)
dir
;
if
(
!
diro
->
inode_read
)
{
grub_ext2_read_inode
(
diro
->
data
,
diro
->
ino
,
&
diro
->
inode
);
if
(
grub_errno
)
return
0
;
}
if
(
diro
->
inode
.
flags
&
grub_cpu_to_le32_compile_time
(
EXT4_ENCRYPT_FLAG
))
{
grub_error
(
GRUB_ERR_NOT_IMPLEMENTED_YET
,
"directory is encrypted"
);
return
0
;
}
/* Search the file. */
while
(
fpos
<
grub_le_to_cpu32
(
diro
->
inode
.
size
))
{
struct
ext2_dirent
dirent
;
grub_ext2_read_file
(
diro
,
0
,
0
,
fpos
,
sizeof
(
struct
ext2_dirent
),
(
char
*
)
&
dirent
);
if
(
grub_errno
)
return
0
;
if
(
dirent
.
direntlen
==
0
)
return
0
;
if
(
dirent
.
inode
!=
0
&&
dirent
.
namelen
!=
0
)
{
char
filename
[
MAX_NAMELEN
+
1
];
struct
grub_fshelp_node
*
fdiro
;
enum
grub_fshelp_filetype
type
=
GRUB_FSHELP_UNKNOWN
;
grub_ext2_read_file
(
diro
,
0
,
0
,
fpos
+
sizeof
(
struct
ext2_dirent
),
dirent
.
namelen
,
filename
);
if
(
grub_errno
)
return
0
;
fdiro
=
grub_malloc
(
sizeof
(
struct
grub_fshelp_node
));
if
(
!
fdiro
)
return
0
;
fdiro
->
data
=
diro
->
data
;
fdiro
->
ino
=
grub_le_to_cpu32
(
dirent
.
inode
);
filename
[
dirent
.
namelen
]
=
'\0'
;
if
(
dirent
.
filetype
!=
FILETYPE_UNKNOWN
)
{
fdiro
->
inode_read
=
0
;
if
(
dirent
.
filetype
==
FILETYPE_DIRECTORY
)
type
=
GRUB_FSHELP_DIR
;
else
if
(
dirent
.
filetype
==
FILETYPE_SYMLINK
)
type
=
GRUB_FSHELP_SYMLINK
;
else
if
(
dirent
.
filetype
==
FILETYPE_REG
)
type
=
GRUB_FSHELP_REG
;
}
else
{
/* The filetype can not be read from the dirent, read
the inode to get more information. */
grub_ext2_read_inode
(
diro
->
data
,
grub_le_to_cpu32
(
dirent
.
inode
),
&
fdiro
->
inode
);
if
(
grub_errno
)
{
grub_free
(
fdiro
);
return
0
;
}
fdiro
->
inode_read
=
1
;
if
((
grub_le_to_cpu16
(
fdiro
->
inode
.
mode
)
&
FILETYPE_INO_MASK
)
==
FILETYPE_INO_DIRECTORY
)
type
=
GRUB_FSHELP_DIR
;
else
if
((
grub_le_to_cpu16
(
fdiro
->
inode
.
mode
)
&
FILETYPE_INO_MASK
)
==
FILETYPE_INO_SYMLINK
)
type
=
GRUB_FSHELP_SYMLINK
;
else
if
((
grub_le_to_cpu16
(
fdiro
->
inode
.
mode
)
&
FILETYPE_INO_MASK
)
==
FILETYPE_INO_REG
)
type
=
GRUB_FSHELP_REG
;
}
if
(
hook
(
filename
,
type
,
fdiro
,
hook_data
))
return
1
;
}
fpos
+=
grub_le_to_cpu16
(
dirent
.
direntlen
);
}
return
0
;
}
/* Open a file named NAME and initialize FILE. */
static
grub_err_t
grub_ext2_open
(
struct
grub_file
*
file
,
const
char
*
name
)
{
struct
grub_ext2_data
*
data
;
struct
grub_fshelp_node
*
fdiro
=
0
;
grub_err_t
err
;
grub_dl_ref
(
my_mod
);
data
=
grub_ext2_mount
(
file
->
device
->
disk
);
if
(
!
data
)
{
err
=
grub_errno
;
goto
fail
;
}
err
=
grub_fshelp_find_file
(
name
,
&
data
->
diropen
,
&
fdiro
,
grub_ext2_iterate_dir
,
grub_ext2_read_symlink
,
GRUB_FSHELP_REG
);
if
(
err
)
goto
fail
;
if
(
!
fdiro
->
inode_read
)
{
err
=
grub_ext2_read_inode
(
data
,
fdiro
->
ino
,
&
fdiro
->
inode
);
if
(
err
)
goto
fail
;
}
if
(
fdiro
->
inode
.
flags
&
grub_cpu_to_le32_compile_time
(
EXT4_ENCRYPT_FLAG
))
{
err
=
grub_error
(
GRUB_ERR_NOT_IMPLEMENTED_YET
,
"file is encrypted"
);
goto
fail
;
}
grub_memcpy
(
data
->
inode
,
&
fdiro
->
inode
,
sizeof
(
struct
grub_ext2_inode
));
grub_free
(
fdiro
);
file
->
size
=
grub_le_to_cpu32
(
data
->
inode
->
size
);
file
->
size
|=
((
grub_off_t
)
grub_le_to_cpu32
(
data
->
inode
->
size_high
))
<<
32
;
file
->
data
=
data
;
file
->
offset
=
0
;
return
0
;
fail:
if
(
fdiro
!=
&
data
->
diropen
)
grub_free
(
fdiro
);
grub_free
(
data
);
grub_dl_unref
(
my_mod
);
return
err
;
}
static
grub_err_t
grub_ext2_close
(
grub_file_t
file
)
{
grub_free
(
file
->
data
);
grub_dl_unref
(
my_mod
);
return
GRUB_ERR_NONE
;
}
/* Read LEN bytes data from FILE into BUF. */
static
grub_ssize_t
grub_ext2_read
(
grub_file_t
file
,
char
*
buf
,
grub_size_t
len
)
{
struct
grub_ext2_data
*
data
=
(
struct
grub_ext2_data
*
)
file
->
data
;
return
grub_ext2_read_file
(
&
data
->
diropen
,
file
->
read_hook
,
file
->
read_hook_data
,
file
->
offset
,
len
,
buf
);
}
/* Context for grub_ext2_dir. */
struct
grub_ext2_dir_ctx
{
grub_fs_dir_hook_t
hook
;
void
*
hook_data
;
struct
grub_ext2_data
*
data
;
};
/* Helper for grub_ext2_dir. */
static
int
grub_ext2_dir_iter
(
const
char
*
filename
,
enum
grub_fshelp_filetype
filetype
,
grub_fshelp_node_t
node
,
void
*
data
)
{
struct
grub_ext2_dir_ctx
*
ctx
=
data
;
struct
grub_dirhook_info
info
;
grub_memset
(
&
info
,
0
,
sizeof
(
info
));
if
(
!
node
->
inode_read
)
{
grub_ext2_read_inode
(
ctx
->
data
,
node
->
ino
,
&
node
->
inode
);
if
(
!
grub_errno
)
node
->
inode_read
=
1
;
grub_errno
=
GRUB_ERR_NONE
;
}
if
(
node
->
inode_read
)
{
info
.
mtimeset
=
1
;
info
.
mtime
=
grub_le_to_cpu32
(
node
->
inode
.
mtime
);
}
info
.
dir
=
((
filetype
&
GRUB_FSHELP_TYPE_MASK
)
==
GRUB_FSHELP_DIR
);
if
(
!
info
.
dir
)
info
.
size
=
(((
grub_off_t
)
grub_le_to_cpu32
(
node
->
inode
.
size_high
))
<<
32
)
|
grub_le_to_cpu32
(
node
->
inode
.
size
);
grub_free
(
node
);
return
ctx
->
hook
(
filename
,
&
info
,
ctx
->
hook_data
);
}
static
grub_err_t
grub_ext2_dir
(
grub_device_t
device
,
const
char
*
path
,
grub_fs_dir_hook_t
hook
,
void
*
hook_data
)
{
struct
grub_ext2_dir_ctx
ctx
=
{
.
hook
=
hook
,
.
hook_data
=
hook_data
};
struct
grub_fshelp_node
*
fdiro
=
0
;
grub_dl_ref
(
my_mod
);
ctx
.
data
=
grub_ext2_mount
(
device
->
disk
);
if
(
!
ctx
.
data
)
goto
fail
;
grub_fshelp_find_file
(
path
,
&
ctx
.
data
->
diropen
,
&
fdiro
,
grub_ext2_iterate_dir
,
grub_ext2_read_symlink
,
GRUB_FSHELP_DIR
);
if
(
grub_errno
)
goto
fail
;
grub_ext2_iterate_dir
(
fdiro
,
grub_ext2_dir_iter
,
&
ctx
);
fail:
if
(
fdiro
!=
&
ctx
.
data
->
diropen
)
grub_free
(
fdiro
);
grub_free
(
ctx
.
data
);
grub_dl_unref
(
my_mod
);
return
grub_errno
;
}
static
grub_err_t
grub_ext2_label
(
grub_device_t
device
,
char
**
label
)
{
struct
grub_ext2_data
*
data
;
grub_disk_t
disk
=
device
->
disk
;
grub_dl_ref
(
my_mod
);
data
=
grub_ext2_mount
(
disk
);
if
(
data
)
*
label
=
grub_strndup
(
data
->
sblock
.
volume_name
,
sizeof
(
data
->
sblock
.
volume_name
));
else
*
label
=
NULL
;
grub_dl_unref
(
my_mod
);
grub_free
(
data
);
return
grub_errno
;
}
static
grub_err_t
grub_ext2_uuid
(
grub_device_t
device
,
char
**
uuid
)
{
struct
grub_ext2_data
*
data
;
grub_disk_t
disk
=
device
->
disk
;
grub_dl_ref
(
my_mod
);
data
=
grub_ext2_mount
(
disk
);
if
(
data
)
{
*
uuid
=
grub_xasprintf
(
"%04x%04x-%04x-%04x-%04x-%04x%04x%04x"
,
grub_be_to_cpu16
(
data
->
sblock
.
uuid
[
0
]),
grub_be_to_cpu16
(
data
->
sblock
.
uuid
[
1
]),
grub_be_to_cpu16
(
data
->
sblock
.
uuid
[
2
]),
grub_be_to_cpu16
(
data
->
sblock
.
uuid
[
3
]),
grub_be_to_cpu16
(
data
->
sblock
.
uuid
[
4
]),
grub_be_to_cpu16
(
data
->
sblock
.
uuid
[
5
]),
grub_be_to_cpu16
(
data
->
sblock
.
uuid
[
6
]),
grub_be_to_cpu16
(
data
->
sblock
.
uuid
[
7
]));
}
else
*
uuid
=
NULL
;
grub_dl_unref
(
my_mod
);
grub_free
(
data
);
return
grub_errno
;
}
/* Get mtime. */
static
grub_err_t
grub_ext2_mtime
(
grub_device_t
device
,
grub_int32_t
*
tm
)
{
struct
grub_ext2_data
*
data
;
grub_disk_t
disk
=
device
->
disk
;
grub_dl_ref
(
my_mod
);
data
=
grub_ext2_mount
(
disk
);
if
(
!
data
)
*
tm
=
0
;
else
*
tm
=
grub_le_to_cpu32
(
data
->
sblock
.
utime
);
grub_dl_unref
(
my_mod
);
grub_free
(
data
);
return
grub_errno
;
}
static
struct
grub_fs
grub_ext2_fs
=
{
.
name
=
"ext2"
,
.
fs_dir
=
grub_ext2_dir
,
.
fs_open
=
grub_ext2_open
,
.
fs_read
=
grub_ext2_read
,
.
fs_close
=
grub_ext2_close
,
.
fs_label
=
grub_ext2_label
,
.
fs_uuid
=
grub_ext2_uuid
,
.
fs_mtime
=
grub_ext2_mtime
,
#ifdef GRUB_UTIL
.
reserved_first_sector
=
1
,
.
blocklist_install
=
1
,
#endif
.
next
=
0
};
GRUB_MOD_INIT
(
ext2
)
{
grub_fs_register
(
&
grub_ext2_fs
);
my_mod
=
mod
;
}
GRUB_MOD_FINI
(
ext2
)
{
grub_fs_unregister
(
&
grub_ext2_fs
);
}
GRUB2/grub-2.04/grub-core/fs/fat.c
View file @
84c50066
...
...
@@ -965,10 +965,8 @@ grub_fat_dir (grub_device_t device, const char *path, grub_fs_dir_hook_t hook,
info
.
dir
=
!!
(
ctxt
.
dir
.
attr
&
GRUB_FAT_ATTR_DIRECTORY
);
info
.
case_insensitive
=
1
;
#ifdef MODE_EXFAT
if
(
!
info
.
dir
)
info
.
size
=
ctxt
.
dir
.
file_size
;
#endif
#ifdef MODE_EXFAT
if
(
!
ctxt
.
dir
.
have_stream
)
...
...
@@ -1276,54 +1274,6 @@ GRUB_MOD_FINI(fat)
#ifdef MODE_EXFAT
static
int
grub_fat_add_chunk
(
ventoy_img_chunk_list
*
chunk_list
,
grub_uint64_t
sector
,
grub_uint64_t
size
,
grub_uint32_t
log_sector_size
)
{
ventoy_img_chunk
*
last_chunk
;
ventoy_img_chunk
*
new_chunk
;
if
(
chunk_list
->
cur_chunk
==
0
)
{
chunk_list
->
chunk
[
0
].
img_start_sector
=
0
;
chunk_list
->
chunk
[
0
].
img_end_sector
=
(
size
>>
11
)
-
1
;
chunk_list
->
chunk
[
0
].
disk_start_sector
=
sector
;
chunk_list
->
chunk
[
0
].
disk_end_sector
=
sector
+
(
size
>>
log_sector_size
)
-
1
;
chunk_list
->
cur_chunk
=
1
;
return
0
;
}
last_chunk
=
chunk_list
->
chunk
+
chunk_list
->
cur_chunk
-
1
;
if
(
last_chunk
->
disk_end_sector
+
1
==
sector
)
{
last_chunk
->
img_end_sector
+=
(
size
>>
11
);
last_chunk
->
disk_end_sector
+=
(
size
>>
log_sector_size
);
return
0
;
}
if
(
chunk_list
->
cur_chunk
==
chunk_list
->
max_chunk
)
{
new_chunk
=
grub_realloc
(
chunk_list
->
chunk
,
chunk_list
->
max_chunk
*
2
*
sizeof
(
ventoy_img_chunk
));
if
(
NULL
==
new_chunk
)
{
return
-
1
;
}
chunk_list
->
chunk
=
new_chunk
;
chunk_list
->
max_chunk
*=
2
;
/* issue: update last_chunk */
last_chunk
=
chunk_list
->
chunk
+
chunk_list
->
cur_chunk
-
1
;
}
new_chunk
=
chunk_list
->
chunk
+
chunk_list
->
cur_chunk
;
new_chunk
->
img_start_sector
=
last_chunk
->
img_end_sector
+
1
;
new_chunk
->
img_end_sector
=
new_chunk
->
img_start_sector
+
(
size
>>
11
)
-
1
;
new_chunk
->
disk_start_sector
=
sector
;
new_chunk
->
disk_end_sector
=
sector
+
(
size
>>
log_sector_size
)
-
1
;
chunk_list
->
cur_chunk
++
;
return
0
;
}
int
grub_fat_get_file_chunk
(
grub_uint64_t
part_start
,
grub_file_t
file
,
ventoy_img_chunk_list
*
chunk_list
)
{
grub_size_t
size
;
...
...
@@ -1433,7 +1383,7 @@ int grub_fat_get_file_chunk(grub_uint64_t part_start, grub_file_t file, ventoy_i
if
(
size
>
len
)
size
=
len
;
grub_
fat_add_chunk
(
chunk_list
,
sector
,
size
,
disk
->
log_sector_size
);
grub_
disk_blocklist_read
(
chunk_list
,
sector
,
size
,
disk
->
log_sector_size
);
len
-=
size
;
logical_cluster
++
;
...
...
GRUB2/grub-2.04/grub-core/fs/ntfs.c
0 → 100644
View file @
84c50066
/* ntfs.c - NTFS filesystem */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2007,2008,2009 Free Software Foundation, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define grub_fshelp_node grub_ntfs_file
#include <grub/file.h>
#include <grub/mm.h>
#include <grub/misc.h>
#include <grub/disk.h>
#include <grub/dl.h>
#include <grub/fshelp.h>
#include <grub/ntfs.h>
#include <grub/charset.h>
GRUB_MOD_LICENSE
(
"GPLv3+"
);
static
grub_dl_t
my_mod
;
#define grub_fshelp_node grub_ntfs_file
static
inline
grub_uint16_t
u16at
(
void
*
ptr
,
grub_size_t
ofs
)
{
return
grub_le_to_cpu16
(
grub_get_unaligned16
((
char
*
)
ptr
+
ofs
));
}
static
inline
grub_uint32_t
u32at
(
void
*
ptr
,
grub_size_t
ofs
)
{
return
grub_le_to_cpu32
(
grub_get_unaligned32
((
char
*
)
ptr
+
ofs
));
}
static
inline
grub_uint64_t
u64at
(
void
*
ptr
,
grub_size_t
ofs
)
{
return
grub_le_to_cpu64
(
grub_get_unaligned64
((
char
*
)
ptr
+
ofs
));
}
grub_ntfscomp_func_t
grub_ntfscomp_func
;
static
grub_err_t
fixup
(
grub_uint8_t
*
buf
,
grub_size_t
len
,
const
grub_uint8_t
*
magic
)
{
grub_uint16_t
ss
;
grub_uint8_t
*
pu
;
grub_uint16_t
us
;
COMPILE_TIME_ASSERT
((
1
<<
GRUB_NTFS_BLK_SHR
)
==
GRUB_DISK_SECTOR_SIZE
);
if
(
grub_memcmp
(
buf
,
magic
,
4
))
return
grub_error
(
GRUB_ERR_BAD_FS
,
"%s label not found"
,
magic
);
ss
=
u16at
(
buf
,
6
)
-
1
;
if
(
ss
!=
len
)
return
grub_error
(
GRUB_ERR_BAD_FS
,
"size not match"
);
pu
=
buf
+
u16at
(
buf
,
4
);
us
=
u16at
(
pu
,
0
);
buf
-=
2
;
while
(
ss
>
0
)
{
buf
+=
GRUB_DISK_SECTOR_SIZE
;
pu
+=
2
;
if
(
u16at
(
buf
,
0
)
!=
us
)
return
grub_error
(
GRUB_ERR_BAD_FS
,
"fixup signature not match"
);
buf
[
0
]
=
pu
[
0
];
buf
[
1
]
=
pu
[
1
];
ss
--
;
}
return
0
;
}
static
grub_err_t
read_mft
(
struct
grub_ntfs_data
*
data
,
grub_uint8_t
*
buf
,
grub_uint64_t
mftno
);
static
grub_err_t
read_attr
(
struct
grub_ntfs_attr
*
at
,
grub_uint8_t
*
dest
,
grub_disk_addr_t
ofs
,
grub_size_t
len
,
int
cached
,
grub_disk_read_hook_t
read_hook
,
void
*
read_hook_data
);
static
grub_err_t
read_data
(
struct
grub_ntfs_attr
*
at
,
grub_uint8_t
*
pa
,
grub_uint8_t
*
dest
,
grub_disk_addr_t
ofs
,
grub_size_t
len
,
int
cached
,
grub_disk_read_hook_t
read_hook
,
void
*
read_hook_data
);
static
void
init_attr
(
struct
grub_ntfs_attr
*
at
,
struct
grub_ntfs_file
*
mft
)
{
at
->
mft
=
mft
;
at
->
flags
=
(
mft
==
&
mft
->
data
->
mmft
)
?
GRUB_NTFS_AF_MMFT
:
0
;
at
->
attr_nxt
=
mft
->
buf
+
u16at
(
mft
->
buf
,
0x14
);
at
->
attr_end
=
at
->
emft_buf
=
at
->
edat_buf
=
at
->
sbuf
=
NULL
;
}
static
void
free_attr
(
struct
grub_ntfs_attr
*
at
)
{
grub_free
(
at
->
emft_buf
);
grub_free
(
at
->
edat_buf
);
grub_free
(
at
->
sbuf
);
}
static
grub_uint8_t
*
find_attr
(
struct
grub_ntfs_attr
*
at
,
grub_uint8_t
attr
)
{
if
(
at
->
flags
&
GRUB_NTFS_AF_ALST
)
{
retry:
while
(
at
->
attr_nxt
<
at
->
attr_end
)
{
at
->
attr_cur
=
at
->
attr_nxt
;
at
->
attr_nxt
+=
u16at
(
at
->
attr_cur
,
4
);
if
((
*
at
->
attr_cur
==
attr
)
||
(
attr
==
0
))
{
grub_uint8_t
*
new_pos
;
if
(
at
->
flags
&
GRUB_NTFS_AF_MMFT
)
{
if
((
grub_disk_read
(
at
->
mft
->
data
->
disk
,
u32at
(
at
->
attr_cur
,
0x10
),
0
,
512
,
at
->
emft_buf
))
||
(
grub_disk_read
(
at
->
mft
->
data
->
disk
,
u32at
(
at
->
attr_cur
,
0x14
),
0
,
512
,
at
->
emft_buf
+
512
)))
return
NULL
;
if
(
fixup
(
at
->
emft_buf
,
at
->
mft
->
data
->
mft_size
,
(
const
grub_uint8_t
*
)
"FILE"
))
return
NULL
;
}
else
{
if
(
read_mft
(
at
->
mft
->
data
,
at
->
emft_buf
,
u32at
(
at
->
attr_cur
,
0x10
)))
return
NULL
;
}
new_pos
=
&
at
->
emft_buf
[
u16at
(
at
->
emft_buf
,
0x14
)];
while
(
*
new_pos
!=
0xFF
)
{
if
((
*
new_pos
==
*
at
->
attr_cur
)
&&
(
u16at
(
new_pos
,
0xE
)
==
u16at
(
at
->
attr_cur
,
0x18
)))
{
return
new_pos
;
}
new_pos
+=
u16at
(
new_pos
,
4
);
}
grub_error
(
GRUB_ERR_BAD_FS
,
"can
\'
t find 0x%X in attribute list"
,
(
unsigned
char
)
*
at
->
attr_cur
);
return
NULL
;
}
}
return
NULL
;
}
at
->
attr_cur
=
at
->
attr_nxt
;
while
(
*
at
->
attr_cur
!=
0xFF
)
{
at
->
attr_nxt
+=
u16at
(
at
->
attr_cur
,
4
);
if
(
*
at
->
attr_cur
==
GRUB_NTFS_AT_ATTRIBUTE_LIST
)
at
->
attr_end
=
at
->
attr_cur
;
if
((
*
at
->
attr_cur
==
attr
)
||
(
attr
==
0
))
return
at
->
attr_cur
;
at
->
attr_cur
=
at
->
attr_nxt
;
}
if
(
at
->
attr_end
)
{
grub_uint8_t
*
pa
;
at
->
emft_buf
=
grub_malloc
(
at
->
mft
->
data
->
mft_size
<<
GRUB_NTFS_BLK_SHR
);
if
(
at
->
emft_buf
==
NULL
)
return
NULL
;
pa
=
at
->
attr_end
;
if
(
pa
[
8
])
{
grub_uint32_t
n
;
n
=
((
u32at
(
pa
,
0x30
)
+
GRUB_DISK_SECTOR_SIZE
-
1
)
&
(
~
(
GRUB_DISK_SECTOR_SIZE
-
1
)));
at
->
attr_cur
=
at
->
attr_end
;
at
->
edat_buf
=
grub_malloc
(
n
);
if
(
!
at
->
edat_buf
)
return
NULL
;
if
(
read_data
(
at
,
pa
,
at
->
edat_buf
,
0
,
n
,
0
,
0
,
0
))
{
grub_error
(
GRUB_ERR_BAD_FS
,
"fail to read non-resident attribute list"
);
return
NULL
;
}
at
->
attr_nxt
=
at
->
edat_buf
;
at
->
attr_end
=
at
->
edat_buf
+
u32at
(
pa
,
0x30
);
}
else
{
at
->
attr_nxt
=
at
->
attr_end
+
u16at
(
pa
,
0x14
);
at
->
attr_end
=
at
->
attr_end
+
u32at
(
pa
,
4
);
}
at
->
flags
|=
GRUB_NTFS_AF_ALST
;
while
(
at
->
attr_nxt
<
at
->
attr_end
)
{
if
((
*
at
->
attr_nxt
==
attr
)
||
(
attr
==
0
))
break
;
at
->
attr_nxt
+=
u16at
(
at
->
attr_nxt
,
4
);
}
if
(
at
->
attr_nxt
>=
at
->
attr_end
)
return
NULL
;
if
((
at
->
flags
&
GRUB_NTFS_AF_MMFT
)
&&
(
attr
==
GRUB_NTFS_AT_DATA
))
{
at
->
flags
|=
GRUB_NTFS_AF_GPOS
;
at
->
attr_cur
=
at
->
attr_nxt
;
pa
=
at
->
attr_cur
;
grub_set_unaligned32
((
char
*
)
pa
+
0x10
,
grub_cpu_to_le32
(
at
->
mft
->
data
->
mft_start
));
grub_set_unaligned32
((
char
*
)
pa
+
0x14
,
grub_cpu_to_le32
(
at
->
mft
->
data
->
mft_start
+
1
));
pa
=
at
->
attr_nxt
+
u16at
(
pa
,
4
);
while
(
pa
<
at
->
attr_end
)
{
if
(
*
pa
!=
attr
)
break
;
if
(
read_attr
(
at
,
pa
+
0x10
,
u32at
(
pa
,
0x10
)
*
(
at
->
mft
->
data
->
mft_size
<<
GRUB_NTFS_BLK_SHR
),
at
->
mft
->
data
->
mft_size
<<
GRUB_NTFS_BLK_SHR
,
0
,
0
,
0
))
return
NULL
;
pa
+=
u16at
(
pa
,
4
);
}
at
->
attr_nxt
=
at
->
attr_cur
;
at
->
flags
&=
~
GRUB_NTFS_AF_GPOS
;
}
goto
retry
;
}
return
NULL
;
}
static
grub_uint8_t
*
locate_attr
(
struct
grub_ntfs_attr
*
at
,
struct
grub_ntfs_file
*
mft
,
grub_uint8_t
attr
)
{
grub_uint8_t
*
pa
;
init_attr
(
at
,
mft
);
pa
=
find_attr
(
at
,
attr
);
if
(
pa
==
NULL
)
return
NULL
;
if
((
at
->
flags
&
GRUB_NTFS_AF_ALST
)
==
0
)
{
while
(
1
)
{
pa
=
find_attr
(
at
,
attr
);
if
(
pa
==
NULL
)
break
;
if
(
at
->
flags
&
GRUB_NTFS_AF_ALST
)
return
pa
;
}
grub_errno
=
GRUB_ERR_NONE
;
free_attr
(
at
);
init_attr
(
at
,
mft
);
pa
=
find_attr
(
at
,
attr
);
}
return
pa
;
}
static
grub_disk_addr_t
read_run_data
(
const
grub_uint8_t
*
run
,
int
nn
,
int
sig
)
{
grub_uint64_t
r
=
0
;
if
(
sig
&&
nn
&&
(
run
[
nn
-
1
]
&
0x80
))
r
=
-
1
;
grub_memcpy
(
&
r
,
run
,
nn
);
return
grub_le_to_cpu64
(
r
);
}
grub_err_t
grub_ntfs_read_run_list
(
struct
grub_ntfs_rlst
*
ctx
)
{
grub_uint8_t
c1
,
c2
;
grub_disk_addr_t
val
;
grub_uint8_t
*
run
;
run
=
ctx
->
cur_run
;
retry:
c1
=
((
*
run
)
&
0x7
);
c2
=
((
*
run
)
>>
4
)
&
0x7
;
run
++
;
if
(
!
c1
)
{
if
((
ctx
->
attr
)
&&
(
ctx
->
attr
->
flags
&
GRUB_NTFS_AF_ALST
))
{
grub_disk_read_hook_t
save_hook
;
save_hook
=
ctx
->
comp
.
disk
->
read_hook
;
ctx
->
comp
.
disk
->
read_hook
=
0
;
run
=
find_attr
(
ctx
->
attr
,
*
ctx
->
attr
->
attr_cur
);
ctx
->
comp
.
disk
->
read_hook
=
save_hook
;
if
(
run
)
{
if
(
run
[
8
]
==
0
)
return
grub_error
(
GRUB_ERR_BAD_FS
,
"$DATA should be non-resident"
);
run
+=
u16at
(
run
,
0x20
);
ctx
->
curr_lcn
=
0
;
goto
retry
;
}
}
return
grub_error
(
GRUB_ERR_BAD_FS
,
"run list overflown"
);
}
ctx
->
curr_vcn
=
ctx
->
next_vcn
;
ctx
->
next_vcn
+=
read_run_data
(
run
,
c1
,
0
);
/* length of current VCN */
run
+=
c1
;
val
=
read_run_data
(
run
,
c2
,
1
);
/* offset to previous LCN */
run
+=
c2
;
ctx
->
curr_lcn
+=
val
;
if
(
val
==
0
)
ctx
->
flags
|=
GRUB_NTFS_RF_BLNK
;
else
ctx
->
flags
&=
~
GRUB_NTFS_RF_BLNK
;
ctx
->
cur_run
=
run
;
return
0
;
}
static
grub_disk_addr_t
grub_ntfs_read_block
(
grub_fshelp_node_t
node
,
grub_disk_addr_t
block
)
{
struct
grub_ntfs_rlst
*
ctx
;
ctx
=
(
struct
grub_ntfs_rlst
*
)
node
;
if
(
block
>=
ctx
->
next_vcn
)
{
if
(
grub_ntfs_read_run_list
(
ctx
))
return
-
1
;
return
ctx
->
curr_lcn
;
}
else
return
(
ctx
->
flags
&
GRUB_NTFS_RF_BLNK
)
?
0
:
(
block
-
ctx
->
curr_vcn
+
ctx
->
curr_lcn
);
}
static
grub_err_t
read_data
(
struct
grub_ntfs_attr
*
at
,
grub_uint8_t
*
pa
,
grub_uint8_t
*
dest
,
grub_disk_addr_t
ofs
,
grub_size_t
len
,
int
cached
,
grub_disk_read_hook_t
read_hook
,
void
*
read_hook_data
)
{
struct
grub_ntfs_rlst
cc
,
*
ctx
;
if
(
len
==
0
)
return
0
;
grub_memset
(
&
cc
,
0
,
sizeof
(
cc
));
ctx
=
&
cc
;
ctx
->
attr
=
at
;
ctx
->
comp
.
log_spc
=
at
->
mft
->
data
->
log_spc
;
ctx
->
comp
.
disk
=
at
->
mft
->
data
->
disk
;
if
(
read_hook
==
grub_file_progress_hook
)
ctx
->
file
=
read_hook_data
;
if
(
pa
[
8
]
==
0
)
{
if
(
ofs
+
len
>
u32at
(
pa
,
0x10
))
return
grub_error
(
GRUB_ERR_BAD_FS
,
"read out of range"
);
grub_memcpy
(
dest
,
pa
+
u32at
(
pa
,
0x14
)
+
ofs
,
len
);
return
0
;
}
ctx
->
cur_run
=
pa
+
u16at
(
pa
,
0x20
);
ctx
->
next_vcn
=
u32at
(
pa
,
0x10
);
ctx
->
curr_lcn
=
0
;
if
((
pa
[
0xC
]
&
GRUB_NTFS_FLAG_COMPRESSED
)
&&
!
(
at
->
flags
&
GRUB_NTFS_AF_GPOS
))
{
if
(
!
cached
)
return
grub_error
(
GRUB_ERR_BAD_FS
,
"attribute can
\'
t be compressed"
);
return
(
grub_ntfscomp_func
)
?
grub_ntfscomp_func
(
dest
,
ofs
,
len
,
ctx
)
:
grub_error
(
GRUB_ERR_BAD_FS
,
N_
(
"module `%s' isn't loaded"
),
"ntfscomp"
);
}
ctx
->
target_vcn
=
ofs
>>
(
GRUB_NTFS_BLK_SHR
+
ctx
->
comp
.
log_spc
);
while
(
ctx
->
next_vcn
<=
ctx
->
target_vcn
)
{
if
(
grub_ntfs_read_run_list
(
ctx
))
return
grub_errno
;
}
if
(
at
->
flags
&
GRUB_NTFS_AF_GPOS
)
{
grub_disk_addr_t
st0
,
st1
;
grub_uint64_t
m
;
m
=
(
ofs
>>
GRUB_NTFS_BLK_SHR
)
&
((
1
<<
ctx
->
comp
.
log_spc
)
-
1
);
st0
=
((
ctx
->
target_vcn
-
ctx
->
curr_vcn
+
ctx
->
curr_lcn
)
<<
ctx
->
comp
.
log_spc
)
+
m
;
st1
=
st0
+
1
;
if
(
st1
==
(
ctx
->
next_vcn
-
ctx
->
curr_vcn
+
ctx
->
curr_lcn
)
<<
ctx
->
comp
.
log_spc
)
{
if
(
grub_ntfs_read_run_list
(
ctx
))
return
grub_errno
;
st1
=
ctx
->
curr_lcn
<<
ctx
->
comp
.
log_spc
;
}
grub_set_unaligned32
(
dest
,
grub_cpu_to_le32
(
st0
));
grub_set_unaligned32
(
dest
+
4
,
grub_cpu_to_le32
(
st1
));
return
0
;
}
grub_fshelp_read_file
(
ctx
->
comp
.
disk
,
(
grub_fshelp_node_t
)
ctx
,
read_hook
,
read_hook_data
,
ofs
,
len
,
(
char
*
)
dest
,
grub_ntfs_read_block
,
ofs
+
len
,
ctx
->
comp
.
log_spc
,
0
);
return
grub_errno
;
}
static
grub_err_t
read_attr
(
struct
grub_ntfs_attr
*
at
,
grub_uint8_t
*
dest
,
grub_disk_addr_t
ofs
,
grub_size_t
len
,
int
cached
,
grub_disk_read_hook_t
read_hook
,
void
*
read_hook_data
)
{
grub_uint8_t
*
save_cur
;
grub_uint8_t
attr
;
grub_uint8_t
*
pp
;
grub_err_t
ret
;
save_cur
=
at
->
attr_cur
;
at
->
attr_nxt
=
at
->
attr_cur
;
attr
=
*
at
->
attr_nxt
;
if
(
at
->
flags
&
GRUB_NTFS_AF_ALST
)
{
grub_uint8_t
*
pa
;
grub_disk_addr_t
vcn
;
/* If compression is possible make sure that we include possible
compressed block size. */
if
(
GRUB_NTFS_LOG_COM_SEC
>=
at
->
mft
->
data
->
log_spc
)
vcn
=
((
ofs
>>
GRUB_NTFS_COM_LOG_LEN
)
<<
(
GRUB_NTFS_LOG_COM_SEC
-
at
->
mft
->
data
->
log_spc
))
&
~
0xFULL
;
else
vcn
=
ofs
>>
(
at
->
mft
->
data
->
log_spc
+
GRUB_NTFS_BLK_SHR
);
pa
=
at
->
attr_nxt
+
u16at
(
at
->
attr_nxt
,
4
);
while
(
pa
<
at
->
attr_end
)
{
if
(
*
pa
!=
attr
)
break
;
if
(
u32at
(
pa
,
8
)
>
vcn
)
break
;
at
->
attr_nxt
=
pa
;
pa
+=
u16at
(
pa
,
4
);
}
}
pp
=
find_attr
(
at
,
attr
);
if
(
pp
)
ret
=
read_data
(
at
,
pp
,
dest
,
ofs
,
len
,
cached
,
read_hook
,
read_hook_data
);
else
ret
=
(
grub_errno
)
?
grub_errno
:
grub_error
(
GRUB_ERR_BAD_FS
,
"attribute not found"
);
at
->
attr_cur
=
save_cur
;
return
ret
;
}
static
grub_err_t
read_mft
(
struct
grub_ntfs_data
*
data
,
grub_uint8_t
*
buf
,
grub_uint64_t
mftno
)
{
if
(
read_attr
(
&
data
->
mmft
.
attr
,
buf
,
mftno
*
((
grub_disk_addr_t
)
data
->
mft_size
<<
GRUB_NTFS_BLK_SHR
),
data
->
mft_size
<<
GRUB_NTFS_BLK_SHR
,
0
,
0
,
0
))
return
grub_error
(
GRUB_ERR_BAD_FS
,
"read MFT 0x%llx fails"
,
(
unsigned
long
long
)
mftno
);
return
fixup
(
buf
,
data
->
mft_size
,
(
const
grub_uint8_t
*
)
"FILE"
);
}
static
grub_err_t
init_file
(
struct
grub_ntfs_file
*
mft
,
grub_uint64_t
mftno
)
{
unsigned
short
flag
;
mft
->
inode_read
=
1
;
mft
->
buf
=
grub_malloc
(
mft
->
data
->
mft_size
<<
GRUB_NTFS_BLK_SHR
);
if
(
mft
->
buf
==
NULL
)
return
grub_errno
;
if
(
read_mft
(
mft
->
data
,
mft
->
buf
,
mftno
))
return
grub_errno
;
flag
=
u16at
(
mft
->
buf
,
0x16
);
if
((
flag
&
1
)
==
0
)
return
grub_error
(
GRUB_ERR_BAD_FS
,
"MFT 0x%llx is not in use"
,
(
unsigned
long
long
)
mftno
);
if
((
flag
&
2
)
==
0
)
{
grub_uint8_t
*
pa
;
pa
=
locate_attr
(
&
mft
->
attr
,
mft
,
GRUB_NTFS_AT_DATA
);
if
(
pa
==
NULL
)
return
grub_error
(
GRUB_ERR_BAD_FS
,
"no $DATA in MFT 0x%llx"
,
(
unsigned
long
long
)
mftno
);
if
(
!
pa
[
8
])
mft
->
size
=
u32at
(
pa
,
0x10
);
else
mft
->
size
=
u64at
(
pa
,
0x30
);
if
((
mft
->
attr
.
flags
&
GRUB_NTFS_AF_ALST
)
==
0
)
mft
->
attr
.
attr_end
=
0
;
/* Don't jump to attribute list */
}
else
init_attr
(
&
mft
->
attr
,
mft
);
return
0
;
}
static
void
free_file
(
struct
grub_ntfs_file
*
mft
)
{
free_attr
(
&
mft
->
attr
);
grub_free
(
mft
->
buf
);
}
static
char
*
get_utf8
(
grub_uint8_t
*
in
,
grub_size_t
len
)
{
grub_uint8_t
*
buf
;
grub_uint16_t
*
tmp
;
grub_size_t
i
;
buf
=
grub_malloc
(
len
*
GRUB_MAX_UTF8_PER_UTF16
+
1
);
tmp
=
grub_malloc
(
len
*
sizeof
(
tmp
[
0
]));
if
(
!
buf
||
!
tmp
)
{
grub_free
(
buf
);
grub_free
(
tmp
);
return
NULL
;
}
for
(
i
=
0
;
i
<
len
;
i
++
)
tmp
[
i
]
=
grub_le_to_cpu16
(
grub_get_unaligned16
(
in
+
2
*
i
));
*
grub_utf16_to_utf8
(
buf
,
tmp
,
len
)
=
'\0'
;
grub_free
(
tmp
);
return
(
char
*
)
buf
;
}
static
int
list_file
(
struct
grub_ntfs_file
*
diro
,
grub_uint8_t
*
pos
,
grub_fshelp_iterate_dir_hook_t
hook
,
void
*
hook_data
)
{
grub_uint8_t
*
np
;
int
ns
;
while
(
1
)
{
grub_uint8_t
namespace
;
char
*
ustr
;
if
(
pos
[
0xC
]
&
2
)
/* end signature */
break
;
np
=
pos
+
0x50
;
ns
=
*
(
np
++
);
namespace
=
*
(
np
++
);
/*
* Ignore files in DOS namespace, as they will reappear as Win32
* names.
*/
if
((
ns
)
&&
(
namespace
!=
2
))
{
enum
grub_fshelp_filetype
type
;
struct
grub_ntfs_file
*
fdiro
;
grub_uint32_t
attr
;
attr
=
u32at
(
pos
,
0x48
);
if
(
attr
&
GRUB_NTFS_ATTR_REPARSE
)
type
=
GRUB_FSHELP_SYMLINK
;
else
if
(
attr
&
GRUB_NTFS_ATTR_DIRECTORY
)
type
=
GRUB_FSHELP_DIR
;
else
type
=
GRUB_FSHELP_REG
;
fdiro
=
grub_zalloc
(
sizeof
(
struct
grub_ntfs_file
));
if
(
!
fdiro
)
return
0
;
fdiro
->
data
=
diro
->
data
;
fdiro
->
ino
=
u64at
(
pos
,
0
)
&
0xffffffffffffULL
;
fdiro
->
mtime
=
u64at
(
pos
,
0x20
);
ustr
=
get_utf8
(
np
,
ns
);
if
(
ustr
==
NULL
)
{
grub_free
(
fdiro
);
return
0
;
}
if
(
namespace
)
type
|=
GRUB_FSHELP_CASE_INSENSITIVE
;
if
(
hook
(
ustr
,
type
,
fdiro
,
hook_data
))
{
grub_free
(
ustr
);
return
1
;
}
grub_free
(
ustr
);
}
pos
+=
u16at
(
pos
,
8
);
}
return
0
;
}
struct
symlink_descriptor
{
grub_uint32_t
type
;
grub_uint32_t
total_len
;
grub_uint16_t
off1
;
grub_uint16_t
len1
;
grub_uint16_t
off2
;
grub_uint16_t
len2
;
}
GRUB_PACKED
;
static
char
*
grub_ntfs_read_symlink
(
grub_fshelp_node_t
node
)
{
struct
grub_ntfs_file
*
mft
;
struct
symlink_descriptor
symdesc
;
grub_err_t
err
;
grub_uint8_t
*
buf16
;
char
*
buf
,
*
end
;
grub_size_t
len
;
grub_uint8_t
*
pa
;
grub_size_t
off
;
mft
=
(
struct
grub_ntfs_file
*
)
node
;
mft
->
buf
=
grub_malloc
(
mft
->
data
->
mft_size
<<
GRUB_NTFS_BLK_SHR
);
if
(
mft
->
buf
==
NULL
)
return
NULL
;
if
(
read_mft
(
mft
->
data
,
mft
->
buf
,
mft
->
ino
))
return
NULL
;
pa
=
locate_attr
(
&
mft
->
attr
,
mft
,
GRUB_NTFS_AT_SYMLINK
);
if
(
pa
==
NULL
)
{
grub_error
(
GRUB_ERR_BAD_FS
,
"no $SYMLINK in MFT 0x%llx"
,
(
unsigned
long
long
)
mft
->
ino
);
return
NULL
;
}
err
=
read_attr
(
&
mft
->
attr
,
(
grub_uint8_t
*
)
&
symdesc
,
0
,
sizeof
(
struct
symlink_descriptor
),
1
,
0
,
0
);
if
(
err
)
return
NULL
;
switch
(
grub_cpu_to_le32
(
symdesc
.
type
))
{
case
0xa000000c
:
off
=
(
sizeof
(
struct
symlink_descriptor
)
+
4
+
grub_cpu_to_le32
(
symdesc
.
off1
));
len
=
grub_cpu_to_le32
(
symdesc
.
len1
);
break
;
case
0xa0000003
:
off
=
(
sizeof
(
struct
symlink_descriptor
)
+
grub_cpu_to_le32
(
symdesc
.
off1
));
len
=
grub_cpu_to_le32
(
symdesc
.
len1
);
break
;
default:
grub_error
(
GRUB_ERR_BAD_FS
,
"symlink type invalid (%x)"
,
grub_cpu_to_le32
(
symdesc
.
type
));
return
NULL
;
}
buf16
=
grub_malloc
(
len
);
if
(
!
buf16
)
return
NULL
;
err
=
read_attr
(
&
mft
->
attr
,
buf16
,
off
,
len
,
1
,
0
,
0
);
if
(
err
)
return
NULL
;
buf
=
get_utf8
(
buf16
,
len
/
2
);
if
(
!
buf
)
{
grub_free
(
buf16
);
return
NULL
;
}
grub_free
(
buf16
);
for
(
end
=
buf
;
*
end
;
end
++
)
if
(
*
end
==
'\\'
)
*
end
=
'/'
;
/* Split the sequence to avoid GCC thinking that this is a trigraph. */
if
(
grub_memcmp
(
buf
,
"/?"
"?/"
,
4
)
==
0
&&
buf
[
5
]
==
':'
&&
buf
[
6
]
==
'/'
&&
grub_isalpha
(
buf
[
4
]))
{
grub_memmove
(
buf
,
buf
+
6
,
end
-
buf
+
1
-
6
);
end
-=
6
;
}
return
buf
;
}
static
int
grub_ntfs_iterate_dir
(
grub_fshelp_node_t
dir
,
grub_fshelp_iterate_dir_hook_t
hook
,
void
*
hook_data
)
{
grub_uint8_t
*
bitmap
;
struct
grub_ntfs_attr
attr
,
*
at
;
grub_uint8_t
*
cur_pos
,
*
indx
,
*
bmp
;
int
ret
=
0
;
grub_size_t
bitmap_len
;
struct
grub_ntfs_file
*
mft
;
mft
=
(
struct
grub_ntfs_file
*
)
dir
;
if
(
!
mft
->
inode_read
)
{
if
(
init_file
(
mft
,
mft
->
ino
))
return
0
;
}
indx
=
NULL
;
bmp
=
NULL
;
at
=
&
attr
;
init_attr
(
at
,
mft
);
while
(
1
)
{
cur_pos
=
find_attr
(
at
,
GRUB_NTFS_AT_INDEX_ROOT
);
if
(
cur_pos
==
NULL
)
{
grub_error
(
GRUB_ERR_BAD_FS
,
"no $INDEX_ROOT"
);
goto
done
;
}
/* Resident, Namelen=4, Offset=0x18, Flags=0x00, Name="$I30" */
if
((
u32at
(
cur_pos
,
8
)
!=
0x180400
)
||
(
u32at
(
cur_pos
,
0x18
)
!=
0x490024
)
||
(
u32at
(
cur_pos
,
0x1C
)
!=
0x300033
))
continue
;
cur_pos
+=
u16at
(
cur_pos
,
0x14
);
if
(
*
cur_pos
!=
0x30
)
/* Not filename index */
continue
;
break
;
}
cur_pos
+=
0x10
;
/* Skip index root */
ret
=
list_file
(
mft
,
cur_pos
+
u16at
(
cur_pos
,
0
),
hook
,
hook_data
);
if
(
ret
)
goto
done
;
bitmap
=
NULL
;
bitmap_len
=
0
;
free_attr
(
at
);
init_attr
(
at
,
mft
);
while
((
cur_pos
=
find_attr
(
at
,
GRUB_NTFS_AT_BITMAP
))
!=
NULL
)
{
int
ofs
;
ofs
=
cur_pos
[
0xA
];
/* Namelen=4, Name="$I30" */
if
((
cur_pos
[
9
]
==
4
)
&&
(
u32at
(
cur_pos
,
ofs
)
==
0x490024
)
&&
(
u32at
(
cur_pos
,
ofs
+
4
)
==
0x300033
))
{
int
is_resident
=
(
cur_pos
[
8
]
==
0
);
bitmap_len
=
((
is_resident
)
?
u32at
(
cur_pos
,
0x10
)
:
u32at
(
cur_pos
,
0x28
));
bmp
=
grub_malloc
(
bitmap_len
);
if
(
bmp
==
NULL
)
goto
done
;
if
(
is_resident
)
{
grub_memcpy
(
bmp
,
cur_pos
+
u16at
(
cur_pos
,
0x14
),
bitmap_len
);
}
else
{
if
(
read_data
(
at
,
cur_pos
,
bmp
,
0
,
bitmap_len
,
0
,
0
,
0
))
{
grub_error
(
GRUB_ERR_BAD_FS
,
"fails to read non-resident $BITMAP"
);
goto
done
;
}
bitmap_len
=
u32at
(
cur_pos
,
0x30
);
}
bitmap
=
bmp
;
break
;
}
}
free_attr
(
at
);
cur_pos
=
locate_attr
(
at
,
mft
,
GRUB_NTFS_AT_INDEX_ALLOCATION
);
while
(
cur_pos
!=
NULL
)
{
/* Non-resident, Namelen=4, Offset=0x40, Flags=0, Name="$I30" */
if
((
u32at
(
cur_pos
,
8
)
==
0x400401
)
&&
(
u32at
(
cur_pos
,
0x40
)
==
0x490024
)
&&
(
u32at
(
cur_pos
,
0x44
)
==
0x300033
))
break
;
cur_pos
=
find_attr
(
at
,
GRUB_NTFS_AT_INDEX_ALLOCATION
);
}
if
((
!
cur_pos
)
&&
(
bitmap
))
{
grub_error
(
GRUB_ERR_BAD_FS
,
"$BITMAP without $INDEX_ALLOCATION"
);
goto
done
;
}
if
(
bitmap
)
{
grub_disk_addr_t
i
;
grub_uint8_t
v
;
indx
=
grub_malloc
(
mft
->
data
->
idx_size
<<
GRUB_NTFS_BLK_SHR
);
if
(
indx
==
NULL
)
goto
done
;
v
=
1
;
for
(
i
=
0
;
i
<
(
grub_disk_addr_t
)
bitmap_len
*
8
;
i
++
)
{
if
(
*
bitmap
&
v
)
{
if
((
read_attr
(
at
,
indx
,
i
*
(
mft
->
data
->
idx_size
<<
GRUB_NTFS_BLK_SHR
),
(
mft
->
data
->
idx_size
<<
GRUB_NTFS_BLK_SHR
),
0
,
0
,
0
))
||
(
fixup
(
indx
,
mft
->
data
->
idx_size
,
(
const
grub_uint8_t
*
)
"INDX"
)))
goto
done
;
ret
=
list_file
(
mft
,
&
indx
[
0x18
+
u16at
(
indx
,
0x18
)],
hook
,
hook_data
);
if
(
ret
)
goto
done
;
}
v
<<=
1
;
if
(
!
v
)
{
v
=
1
;
bitmap
++
;
}
}
}
done:
free_attr
(
at
);
grub_free
(
indx
);
grub_free
(
bmp
);
return
ret
;
}
static
struct
grub_ntfs_data
*
grub_ntfs_mount
(
grub_disk_t
disk
)
{
struct
grub_ntfs_bpb
bpb
;
struct
grub_ntfs_data
*
data
=
0
;
grub_uint32_t
spc
;
if
(
!
disk
)
goto
fail
;
data
=
(
struct
grub_ntfs_data
*
)
grub_zalloc
(
sizeof
(
*
data
));
if
(
!
data
)
goto
fail
;
data
->
disk
=
disk
;
/* Read the BPB. */
if
(
grub_disk_read
(
disk
,
0
,
0
,
sizeof
(
bpb
),
&
bpb
))
goto
fail
;
if
(
grub_memcmp
((
char
*
)
&
bpb
.
oem_name
,
"NTFS"
,
4
)
!=
0
||
bpb
.
sectors_per_cluster
==
0
||
(
bpb
.
sectors_per_cluster
&
(
bpb
.
sectors_per_cluster
-
1
))
!=
0
||
bpb
.
bytes_per_sector
==
0
||
(
bpb
.
bytes_per_sector
&
(
bpb
.
bytes_per_sector
-
1
))
!=
0
)
goto
fail
;
spc
=
(((
grub_uint32_t
)
bpb
.
sectors_per_cluster
*
(
grub_uint32_t
)
grub_le_to_cpu16
(
bpb
.
bytes_per_sector
))
>>
GRUB_NTFS_BLK_SHR
);
if
(
spc
==
0
)
goto
fail
;
for
(
data
->
log_spc
=
0
;
(
1U
<<
data
->
log_spc
)
<
spc
;
data
->
log_spc
++
);
if
(
bpb
.
clusters_per_mft
>
0
)
data
->
mft_size
=
((
grub_disk_addr_t
)
bpb
.
clusters_per_mft
)
<<
data
->
log_spc
;
else
if
(
-
bpb
.
clusters_per_mft
<
GRUB_NTFS_BLK_SHR
||
-
bpb
.
clusters_per_mft
>=
31
)
goto
fail
;
else
data
->
mft_size
=
1ULL
<<
(
-
bpb
.
clusters_per_mft
-
GRUB_NTFS_BLK_SHR
);
if
(
bpb
.
clusters_per_index
>
0
)
data
->
idx_size
=
(((
grub_disk_addr_t
)
bpb
.
clusters_per_index
)
<<
data
->
log_spc
);
else
if
(
-
bpb
.
clusters_per_index
<
GRUB_NTFS_BLK_SHR
||
-
bpb
.
clusters_per_index
>=
31
)
goto
fail
;
else
data
->
idx_size
=
1ULL
<<
(
-
bpb
.
clusters_per_index
-
GRUB_NTFS_BLK_SHR
);
data
->
mft_start
=
grub_le_to_cpu64
(
bpb
.
mft_lcn
)
<<
data
->
log_spc
;
if
((
data
->
mft_size
>
GRUB_NTFS_MAX_MFT
)
||
(
data
->
idx_size
>
GRUB_NTFS_MAX_IDX
))
goto
fail
;
data
->
mmft
.
data
=
data
;
data
->
cmft
.
data
=
data
;
data
->
mmft
.
buf
=
grub_malloc
(
data
->
mft_size
<<
GRUB_NTFS_BLK_SHR
);
if
(
!
data
->
mmft
.
buf
)
goto
fail
;
if
(
grub_disk_read
(
disk
,
data
->
mft_start
,
0
,
data
->
mft_size
<<
GRUB_NTFS_BLK_SHR
,
data
->
mmft
.
buf
))
goto
fail
;
data
->
uuid
=
grub_le_to_cpu64
(
bpb
.
num_serial
);
if
(
fixup
(
data
->
mmft
.
buf
,
data
->
mft_size
,
(
const
grub_uint8_t
*
)
"FILE"
))
goto
fail
;
if
(
!
locate_attr
(
&
data
->
mmft
.
attr
,
&
data
->
mmft
,
GRUB_NTFS_AT_DATA
))
goto
fail
;
if
(
init_file
(
&
data
->
cmft
,
GRUB_NTFS_FILE_ROOT
))
goto
fail
;
return
data
;
fail:
grub_error
(
GRUB_ERR_BAD_FS
,
"not an ntfs filesystem"
);
if
(
data
)
{
free_file
(
&
data
->
mmft
);
free_file
(
&
data
->
cmft
);
grub_free
(
data
);
}
return
0
;
}
/* Context for grub_ntfs_dir. */
struct
grub_ntfs_dir_ctx
{
grub_fs_dir_hook_t
hook
;
void
*
hook_data
;
};
/* Helper for grub_ntfs_dir. */
static
int
grub_ntfs_dir_iter
(
const
char
*
filename
,
enum
grub_fshelp_filetype
filetype
,
grub_fshelp_node_t
node
,
void
*
data
)
{
struct
grub_ntfs_dir_ctx
*
ctx
=
data
;
struct
grub_dirhook_info
info
;
grub_memset
(
&
info
,
0
,
sizeof
(
info
));
info
.
dir
=
((
filetype
&
GRUB_FSHELP_TYPE_MASK
)
==
GRUB_FSHELP_DIR
);
info
.
mtimeset
=
1
;
info
.
mtime
=
grub_divmod64
(
node
->
mtime
,
10000000
,
0
)
-
86400ULL
*
365
*
(
1970
-
1601
)
-
86400ULL
*
((
1970
-
1601
)
/
4
)
+
86400ULL
*
((
1970
-
1601
)
/
100
);
if
(
!
info
.
dir
)
info
.
size
=
node
->
size
;
grub_free
(
node
);
return
ctx
->
hook
(
filename
,
&
info
,
ctx
->
hook_data
);
}
static
grub_err_t
grub_ntfs_dir
(
grub_device_t
device
,
const
char
*
path
,
grub_fs_dir_hook_t
hook
,
void
*
hook_data
)
{
struct
grub_ntfs_dir_ctx
ctx
=
{
hook
,
hook_data
};
struct
grub_ntfs_data
*
data
=
0
;
struct
grub_fshelp_node
*
fdiro
=
0
;
grub_dl_ref
(
my_mod
);
data
=
grub_ntfs_mount
(
device
->
disk
);
if
(
!
data
)
goto
fail
;
grub_fshelp_find_file
(
path
,
&
data
->
cmft
,
&
fdiro
,
grub_ntfs_iterate_dir
,
grub_ntfs_read_symlink
,
GRUB_FSHELP_DIR
);
if
(
grub_errno
)
goto
fail
;
grub_ntfs_iterate_dir
(
fdiro
,
grub_ntfs_dir_iter
,
&
ctx
);
fail:
if
((
fdiro
)
&&
(
fdiro
!=
&
data
->
cmft
))
{
free_file
(
fdiro
);
grub_free
(
fdiro
);
}
if
(
data
)
{
free_file
(
&
data
->
mmft
);
free_file
(
&
data
->
cmft
);
grub_free
(
data
);
}
grub_dl_unref
(
my_mod
);
return
grub_errno
;
}
static
grub_err_t
grub_ntfs_open
(
grub_file_t
file
,
const
char
*
name
)
{
struct
grub_ntfs_data
*
data
=
0
;
struct
grub_fshelp_node
*
mft
=
0
;
grub_dl_ref
(
my_mod
);
data
=
grub_ntfs_mount
(
file
->
device
->
disk
);
if
(
!
data
)
goto
fail
;
grub_fshelp_find_file
(
name
,
&
data
->
cmft
,
&
mft
,
grub_ntfs_iterate_dir
,
grub_ntfs_read_symlink
,
GRUB_FSHELP_REG
);
if
(
grub_errno
)
goto
fail
;
if
(
mft
!=
&
data
->
cmft
)
{
free_file
(
&
data
->
cmft
);
grub_memcpy
(
&
data
->
cmft
,
mft
,
sizeof
(
*
mft
));
grub_free
(
mft
);
if
(
!
data
->
cmft
.
inode_read
)
{
if
(
init_file
(
&
data
->
cmft
,
data
->
cmft
.
ino
))
goto
fail
;
}
}
file
->
size
=
data
->
cmft
.
size
;
file
->
data
=
data
;
file
->
offset
=
0
;
return
0
;
fail:
if
(
data
)
{
free_file
(
&
data
->
mmft
);
free_file
(
&
data
->
cmft
);
grub_free
(
data
);
}
grub_dl_unref
(
my_mod
);
return
grub_errno
;
}
static
grub_ssize_t
grub_ntfs_read
(
grub_file_t
file
,
char
*
buf
,
grub_size_t
len
)
{
struct
grub_ntfs_file
*
mft
;
mft
=
&
((
struct
grub_ntfs_data
*
)
file
->
data
)
->
cmft
;
if
(
file
->
read_hook
)
mft
->
attr
.
save_pos
=
1
;
read_attr
(
&
mft
->
attr
,
(
grub_uint8_t
*
)
buf
,
file
->
offset
,
len
,
1
,
file
->
read_hook
,
file
->
read_hook_data
);
return
(
grub_errno
)
?
-
1
:
(
grub_ssize_t
)
len
;
}
static
grub_err_t
grub_ntfs_close
(
grub_file_t
file
)
{
struct
grub_ntfs_data
*
data
;
data
=
file
->
data
;
if
(
data
)
{
free_file
(
&
data
->
mmft
);
free_file
(
&
data
->
cmft
);
grub_free
(
data
);
}
grub_dl_unref
(
my_mod
);
return
grub_errno
;
}
static
grub_err_t
grub_ntfs_label
(
grub_device_t
device
,
char
**
label
)
{
struct
grub_ntfs_data
*
data
=
0
;
struct
grub_fshelp_node
*
mft
=
0
;
grub_uint8_t
*
pa
;
grub_dl_ref
(
my_mod
);
*
label
=
0
;
data
=
grub_ntfs_mount
(
device
->
disk
);
if
(
!
data
)
goto
fail
;
grub_fshelp_find_file
(
"/$Volume"
,
&
data
->
cmft
,
&
mft
,
grub_ntfs_iterate_dir
,
0
,
GRUB_FSHELP_REG
);
if
(
grub_errno
)
goto
fail
;
if
(
!
mft
->
inode_read
)
{
mft
->
buf
=
grub_malloc
(
mft
->
data
->
mft_size
<<
GRUB_NTFS_BLK_SHR
);
if
(
mft
->
buf
==
NULL
)
goto
fail
;
if
(
read_mft
(
mft
->
data
,
mft
->
buf
,
mft
->
ino
))
goto
fail
;
}
init_attr
(
&
mft
->
attr
,
mft
);
pa
=
find_attr
(
&
mft
->
attr
,
GRUB_NTFS_AT_VOLUME_NAME
);
if
((
pa
)
&&
(
pa
[
8
]
==
0
)
&&
(
u32at
(
pa
,
0x10
)))
{
int
len
;
len
=
u32at
(
pa
,
0x10
)
/
2
;
pa
+=
u16at
(
pa
,
0x14
);
*
label
=
get_utf8
(
pa
,
len
);
}
fail:
if
((
mft
)
&&
(
mft
!=
&
data
->
cmft
))
{
free_file
(
mft
);
grub_free
(
mft
);
}
if
(
data
)
{
free_file
(
&
data
->
mmft
);
free_file
(
&
data
->
cmft
);
grub_free
(
data
);
}
grub_dl_unref
(
my_mod
);
return
grub_errno
;
}
static
grub_err_t
grub_ntfs_uuid
(
grub_device_t
device
,
char
**
uuid
)
{
struct
grub_ntfs_data
*
data
;
grub_disk_t
disk
=
device
->
disk
;
grub_dl_ref
(
my_mod
);
data
=
grub_ntfs_mount
(
disk
);
if
(
data
)
{
char
*
ptr
;
*
uuid
=
grub_xasprintf
(
"%016llx"
,
(
unsigned
long
long
)
data
->
uuid
);
if
(
*
uuid
)
for
(
ptr
=
*
uuid
;
*
ptr
;
ptr
++
)
*
ptr
=
grub_toupper
(
*
ptr
);
free_file
(
&
data
->
mmft
);
free_file
(
&
data
->
cmft
);
grub_free
(
data
);
}
else
*
uuid
=
NULL
;
grub_dl_unref
(
my_mod
);
return
grub_errno
;
}
static
struct
grub_fs
grub_ntfs_fs
=
{
.
name
=
"ntfs"
,
.
fs_dir
=
grub_ntfs_dir
,
.
fs_open
=
grub_ntfs_open
,
.
fs_read
=
grub_ntfs_read
,
.
fs_close
=
grub_ntfs_close
,
.
fs_label
=
grub_ntfs_label
,
.
fs_uuid
=
grub_ntfs_uuid
,
#ifdef GRUB_UTIL
.
reserved_first_sector
=
1
,
.
blocklist_install
=
1
,
#endif
.
next
=
0
};
GRUB_MOD_INIT
(
ntfs
)
{
grub_fs_register
(
&
grub_ntfs_fs
);
my_mod
=
mod
;
}
GRUB_MOD_FINI
(
ntfs
)
{
grub_fs_unregister
(
&
grub_ntfs_fs
);
}
GRUB2/grub-2.04/grub-core/fs/udf.c
View file @
84c50066
...
...
@@ -1152,6 +1152,8 @@ grub_udf_dir_iter (const char *filename, enum grub_fshelp_filetype filetype,
info
.
mtime
-=
60
*
tz
;
}
if
(
!
info
.
dir
)
info
.
size
=
U64
(
node
->
block
.
fe
.
file_size
);
grub_free
(
node
);
return
ctx
->
hook
(
filename
,
&
info
,
ctx
->
hook_data
);
}
...
...
GRUB2/grub-2.04/grub-core/fs/xfs.c
0 → 100644
View file @
84c50066
/* xfs.c - XFS. */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2005,2006,2007,2008,2009 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <grub/err.h>
#include <grub/file.h>
#include <grub/mm.h>
#include <grub/misc.h>
#include <grub/disk.h>
#include <grub/dl.h>
#include <grub/types.h>
#include <grub/fshelp.h>
GRUB_MOD_LICENSE
(
"GPLv3+"
);
#define XFS_INODE_EXTENTS 9
#define XFS_INODE_FORMAT_INO 1
#define XFS_INODE_FORMAT_EXT 2
#define XFS_INODE_FORMAT_BTREE 3
/* Superblock version field flags */
#define XFS_SB_VERSION_NUMBITS 0x000f
#define XFS_SB_VERSION_ATTRBIT 0x0010
#define XFS_SB_VERSION_NLINKBIT 0x0020
#define XFS_SB_VERSION_QUOTABIT 0x0040
#define XFS_SB_VERSION_ALIGNBIT 0x0080
#define XFS_SB_VERSION_DALIGNBIT 0x0100
#define XFS_SB_VERSION_LOGV2BIT 0x0400
#define XFS_SB_VERSION_SECTORBIT 0x0800
#define XFS_SB_VERSION_EXTFLGBIT 0x1000
#define XFS_SB_VERSION_DIRV2BIT 0x2000
#define XFS_SB_VERSION_MOREBITSBIT 0x8000
#define XFS_SB_VERSION_BITS_SUPPORTED \
(XFS_SB_VERSION_NUMBITS | \
XFS_SB_VERSION_ATTRBIT | \
XFS_SB_VERSION_NLINKBIT | \
XFS_SB_VERSION_QUOTABIT | \
XFS_SB_VERSION_ALIGNBIT | \
XFS_SB_VERSION_DALIGNBIT | \
XFS_SB_VERSION_LOGV2BIT | \
XFS_SB_VERSION_SECTORBIT | \
XFS_SB_VERSION_EXTFLGBIT | \
XFS_SB_VERSION_DIRV2BIT | \
XFS_SB_VERSION_MOREBITSBIT)
/* Recognized xfs format versions */
#define XFS_SB_VERSION_4 4
/* Good old XFS filesystem */
#define XFS_SB_VERSION_5 5
/* CRC enabled filesystem */
/* features2 field flags */
#define XFS_SB_VERSION2_LAZYSBCOUNTBIT 0x00000002
/* Superblk counters */
#define XFS_SB_VERSION2_ATTR2BIT 0x00000008
/* Inline attr rework */
#define XFS_SB_VERSION2_PROJID32BIT 0x00000080
/* 32-bit project ids */
#define XFS_SB_VERSION2_FTYPE 0x00000200
/* inode type in dir */
#define XFS_SB_VERSION2_BITS_SUPPORTED \
(XFS_SB_VERSION2_LAZYSBCOUNTBIT | \
XFS_SB_VERSION2_ATTR2BIT | \
XFS_SB_VERSION2_PROJID32BIT | \
XFS_SB_VERSION2_FTYPE)
/* incompat feature flags */
#define XFS_SB_FEAT_INCOMPAT_FTYPE (1 << 0)
/* filetype in dirent */
#define XFS_SB_FEAT_INCOMPAT_SPINODES (1 << 1)
/* sparse inode chunks */
#define XFS_SB_FEAT_INCOMPAT_META_UUID (1 << 2)
/* metadata UUID */
/*
* Directory entries with ftype are explicitly handled by GRUB code.
*
* We do not currently read the inode btrees, so it is safe to read filesystems
* with the XFS_SB_FEAT_INCOMPAT_SPINODES feature.
*
* We do not currently verify metadata UUID, so it is safe to read filesystems
* with the XFS_SB_FEAT_INCOMPAT_META_UUID feature.
*/
#define XFS_SB_FEAT_INCOMPAT_SUPPORTED \
(XFS_SB_FEAT_INCOMPAT_FTYPE | \
XFS_SB_FEAT_INCOMPAT_SPINODES | \
XFS_SB_FEAT_INCOMPAT_META_UUID)
struct
grub_xfs_sblock
{
grub_uint8_t
magic
[
4
];
grub_uint32_t
bsize
;
grub_uint8_t
unused1
[
24
];
grub_uint16_t
uuid
[
8
];
grub_uint8_t
unused2
[
8
];
grub_uint64_t
rootino
;
grub_uint8_t
unused3
[
20
];
grub_uint32_t
agsize
;
grub_uint8_t
unused4
[
12
];
grub_uint16_t
version
;
grub_uint8_t
unused5
[
6
];
grub_uint8_t
label
[
12
];
grub_uint8_t
log2_bsize
;
grub_uint8_t
log2_sect
;
grub_uint8_t
log2_inode
;
grub_uint8_t
log2_inop
;
grub_uint8_t
log2_agblk
;
grub_uint8_t
unused6
[
67
];
grub_uint8_t
log2_dirblk
;
grub_uint8_t
unused7
[
7
];
grub_uint32_t
features2
;
grub_uint8_t
unused8
[
4
];
grub_uint32_t
sb_features_compat
;
grub_uint32_t
sb_features_ro_compat
;
grub_uint32_t
sb_features_incompat
;
grub_uint32_t
sb_features_log_incompat
;
}
GRUB_PACKED
;
struct
grub_xfs_dir_header
{
grub_uint8_t
count
;
grub_uint8_t
largeino
;
union
{
grub_uint32_t
i4
;
grub_uint64_t
i8
;
}
GRUB_PACKED
parent
;
}
GRUB_PACKED
;
/* Structure for directory entry inlined in the inode */
struct
grub_xfs_dir_entry
{
grub_uint8_t
len
;
grub_uint16_t
offset
;
char
name
[
1
];
/* Inode number follows, 32 / 64 bits. */
}
GRUB_PACKED
;
/* Structure for directory entry in a block */
struct
grub_xfs_dir2_entry
{
grub_uint64_t
inode
;
grub_uint8_t
len
;
}
GRUB_PACKED
;
struct
grub_xfs_extent
{
/* This should be a bitfield but bietfields are unportable, so just have
a raw array and functions extracting useful info from it.
*/
grub_uint32_t
raw
[
4
];
}
GRUB_PACKED
;
struct
grub_xfs_btree_node
{
grub_uint8_t
magic
[
4
];
grub_uint16_t
level
;
grub_uint16_t
numrecs
;
grub_uint64_t
left
;
grub_uint64_t
right
;
/* In V5 here follow crc, uuid, etc. */
/* Then follow keys and block pointers */
}
GRUB_PACKED
;
struct
grub_xfs_btree_root
{
grub_uint16_t
level
;
grub_uint16_t
numrecs
;
grub_uint64_t
keys
[
1
];
}
GRUB_PACKED
;
struct
grub_xfs_time
{
grub_uint32_t
sec
;
grub_uint32_t
nanosec
;
}
GRUB_PACKED
;
struct
grub_xfs_inode
{
grub_uint8_t
magic
[
2
];
grub_uint16_t
mode
;
grub_uint8_t
version
;
grub_uint8_t
format
;
grub_uint8_t
unused2
[
26
];
struct
grub_xfs_time
atime
;
struct
grub_xfs_time
mtime
;
struct
grub_xfs_time
ctime
;
grub_uint64_t
size
;
grub_uint64_t
nblocks
;
grub_uint32_t
extsize
;
grub_uint32_t
nextents
;
grub_uint16_t
unused3
;
grub_uint8_t
fork_offset
;
grub_uint8_t
unused4
[
17
];
}
GRUB_PACKED
;
#define XFS_V2_INODE_SIZE sizeof(struct grub_xfs_inode)
#define XFS_V3_INODE_SIZE (XFS_V2_INODE_SIZE + 76)
struct
grub_xfs_dirblock_tail
{
grub_uint32_t
leaf_count
;
grub_uint32_t
leaf_stale
;
}
GRUB_PACKED
;
struct
grub_fshelp_node
{
struct
grub_xfs_data
*
data
;
grub_uint64_t
ino
;
int
inode_read
;
struct
grub_xfs_inode
inode
;
};
struct
grub_xfs_data
{
struct
grub_xfs_sblock
sblock
;
grub_disk_t
disk
;
int
pos
;
int
bsize
;
grub_uint32_t
agsize
;
unsigned
int
hasftype
:
1
;
unsigned
int
hascrc
:
1
;
struct
grub_fshelp_node
diropen
;
};
static
grub_dl_t
my_mod
;
static
int
grub_xfs_sb_hascrc
(
struct
grub_xfs_data
*
data
)
{
return
(
data
->
sblock
.
version
&
grub_cpu_to_be16_compile_time
(
XFS_SB_VERSION_NUMBITS
))
==
grub_cpu_to_be16_compile_time
(
XFS_SB_VERSION_5
);
}
static
int
grub_xfs_sb_hasftype
(
struct
grub_xfs_data
*
data
)
{
if
((
data
->
sblock
.
version
&
grub_cpu_to_be16_compile_time
(
XFS_SB_VERSION_NUMBITS
))
==
grub_cpu_to_be16_compile_time
(
XFS_SB_VERSION_5
)
&&
data
->
sblock
.
sb_features_incompat
&
grub_cpu_to_be32_compile_time
(
XFS_SB_FEAT_INCOMPAT_FTYPE
))
return
1
;
if
(
data
->
sblock
.
version
&
grub_cpu_to_be16_compile_time
(
XFS_SB_VERSION_MOREBITSBIT
)
&&
data
->
sblock
.
features2
&
grub_cpu_to_be32_compile_time
(
XFS_SB_VERSION2_FTYPE
))
return
1
;
return
0
;
}
static
int
grub_xfs_sb_valid
(
struct
grub_xfs_data
*
data
)
{
grub_dprintf
(
"xfs"
,
"Validating superblock
\n
"
);
if
(
grub_strncmp
((
char
*
)
(
data
->
sblock
.
magic
),
"XFSB"
,
4
)
||
data
->
sblock
.
log2_bsize
<
GRUB_DISK_SECTOR_BITS
||
((
int
)
data
->
sblock
.
log2_bsize
+
(
int
)
data
->
sblock
.
log2_dirblk
)
>=
27
)
{
grub_error
(
GRUB_ERR_BAD_FS
,
"not a XFS filesystem"
);
return
0
;
}
if
((
data
->
sblock
.
version
&
grub_cpu_to_be16_compile_time
(
XFS_SB_VERSION_NUMBITS
))
==
grub_cpu_to_be16_compile_time
(
XFS_SB_VERSION_5
))
{
grub_dprintf
(
"xfs"
,
"XFS v5 superblock detected
\n
"
);
if
(
data
->
sblock
.
sb_features_incompat
&
grub_cpu_to_be32_compile_time
(
~
XFS_SB_FEAT_INCOMPAT_SUPPORTED
))
{
grub_error
(
GRUB_ERR_BAD_FS
,
"XFS filesystem has unsupported "
"incompatible features"
);
return
0
;
}
return
1
;
}
else
if
((
data
->
sblock
.
version
&
grub_cpu_to_be16_compile_time
(
XFS_SB_VERSION_NUMBITS
))
==
grub_cpu_to_be16_compile_time
(
XFS_SB_VERSION_4
))
{
grub_dprintf
(
"xfs"
,
"XFS v4 superblock detected
\n
"
);
if
(
!
(
data
->
sblock
.
version
&
grub_cpu_to_be16_compile_time
(
XFS_SB_VERSION_DIRV2BIT
)))
{
grub_error
(
GRUB_ERR_BAD_FS
,
"XFS filesystem without V2 directories "
"is unsupported"
);
return
0
;
}
if
(
data
->
sblock
.
version
&
grub_cpu_to_be16_compile_time
(
~
XFS_SB_VERSION_BITS_SUPPORTED
)
||
(
data
->
sblock
.
version
&
grub_cpu_to_be16_compile_time
(
XFS_SB_VERSION_MOREBITSBIT
)
&&
data
->
sblock
.
features2
&
grub_cpu_to_be16_compile_time
(
~
XFS_SB_VERSION2_BITS_SUPPORTED
)))
{
grub_error
(
GRUB_ERR_BAD_FS
,
"XFS filesystem has unsupported version "
"bits"
);
return
0
;
}
return
1
;
}
return
0
;
}
/* Filetype information as used in inodes. */
#define FILETYPE_INO_MASK 0170000
#define FILETYPE_INO_REG 0100000
#define FILETYPE_INO_DIRECTORY 0040000
#define FILETYPE_INO_SYMLINK 0120000
static
inline
int
GRUB_XFS_INO_AGBITS
(
struct
grub_xfs_data
*
data
)
{
return
((
data
)
->
sblock
.
log2_agblk
+
(
data
)
->
sblock
.
log2_inop
);
}
static
inline
grub_uint64_t
GRUB_XFS_INO_INOINAG
(
struct
grub_xfs_data
*
data
,
grub_uint64_t
ino
)
{
return
(
ino
&
((
1LL
<<
GRUB_XFS_INO_AGBITS
(
data
))
-
1
));
}
static
inline
grub_uint64_t
GRUB_XFS_INO_AG
(
struct
grub_xfs_data
*
data
,
grub_uint64_t
ino
)
{
return
(
ino
>>
GRUB_XFS_INO_AGBITS
(
data
));
}
static
inline
grub_disk_addr_t
GRUB_XFS_FSB_TO_BLOCK
(
struct
grub_xfs_data
*
data
,
grub_disk_addr_t
fsb
)
{
return
((
fsb
>>
data
->
sblock
.
log2_agblk
)
*
data
->
agsize
+
(
fsb
&
((
1LL
<<
data
->
sblock
.
log2_agblk
)
-
1
)));
}
static
inline
grub_uint64_t
GRUB_XFS_EXTENT_OFFSET
(
struct
grub_xfs_extent
*
exts
,
int
ex
)
{
return
((
grub_be_to_cpu32
(
exts
[
ex
].
raw
[
0
])
&
~
(
1
<<
31
))
<<
23
|
grub_be_to_cpu32
(
exts
[
ex
].
raw
[
1
])
>>
9
);
}
static
inline
grub_uint64_t
GRUB_XFS_EXTENT_BLOCK
(
struct
grub_xfs_extent
*
exts
,
int
ex
)
{
return
((
grub_uint64_t
)
(
grub_be_to_cpu32
(
exts
[
ex
].
raw
[
1
])
&
(
0x1ff
))
<<
43
|
(
grub_uint64_t
)
grub_be_to_cpu32
(
exts
[
ex
].
raw
[
2
])
<<
11
|
grub_be_to_cpu32
(
exts
[
ex
].
raw
[
3
])
>>
21
);
}
static
inline
grub_uint64_t
GRUB_XFS_EXTENT_SIZE
(
struct
grub_xfs_extent
*
exts
,
int
ex
)
{
return
(
grub_be_to_cpu32
(
exts
[
ex
].
raw
[
3
])
&
((
1
<<
21
)
-
1
));
}
static
inline
grub_uint64_t
grub_xfs_inode_block
(
struct
grub_xfs_data
*
data
,
grub_uint64_t
ino
)
{
long
long
int
inoinag
=
GRUB_XFS_INO_INOINAG
(
data
,
ino
);
long
long
ag
=
GRUB_XFS_INO_AG
(
data
,
ino
);
long
long
block
;
block
=
(
inoinag
>>
data
->
sblock
.
log2_inop
)
+
ag
*
data
->
agsize
;
block
<<=
(
data
->
sblock
.
log2_bsize
-
GRUB_DISK_SECTOR_BITS
);
return
block
;
}
static
inline
int
grub_xfs_inode_offset
(
struct
grub_xfs_data
*
data
,
grub_uint64_t
ino
)
{
int
inoag
=
GRUB_XFS_INO_INOINAG
(
data
,
ino
);
return
((
inoag
&
((
1
<<
data
->
sblock
.
log2_inop
)
-
1
))
<<
data
->
sblock
.
log2_inode
);
}
static
inline
grub_size_t
grub_xfs_inode_size
(
struct
grub_xfs_data
*
data
)
{
return
(
grub_size_t
)
1
<<
data
->
sblock
.
log2_inode
;
}
/*
* Returns size occupied by XFS inode stored in memory - we store struct
* grub_fshelp_node there but on disk inode size may be actually larger than
* struct grub_xfs_inode so we need to account for that so that we can read
* from disk directly into in-memory structure.
*/
static
inline
grub_size_t
grub_xfs_fshelp_size
(
struct
grub_xfs_data
*
data
)
{
return
sizeof
(
struct
grub_fshelp_node
)
-
sizeof
(
struct
grub_xfs_inode
)
+
grub_xfs_inode_size
(
data
);
}
/* This should return void * but XFS code is error-prone with alignment, so
return char to retain cast-align.
*/
static
char
*
grub_xfs_inode_data
(
struct
grub_xfs_inode
*
inode
)
{
if
(
inode
->
version
<=
2
)
return
((
char
*
)
inode
)
+
XFS_V2_INODE_SIZE
;
return
((
char
*
)
inode
)
+
XFS_V3_INODE_SIZE
;
}
static
struct
grub_xfs_dir_entry
*
grub_xfs_inline_de
(
struct
grub_xfs_dir_header
*
head
)
{
/*
With small inode numbers the header is 4 bytes smaller because of
smaller parent pointer
*/
return
(
struct
grub_xfs_dir_entry
*
)
(((
char
*
)
head
)
+
sizeof
(
struct
grub_xfs_dir_header
)
-
(
head
->
largeino
?
0
:
sizeof
(
grub_uint32_t
)));
}
static
grub_uint8_t
*
grub_xfs_inline_de_inopos
(
struct
grub_xfs_data
*
data
,
struct
grub_xfs_dir_entry
*
de
)
{
return
((
grub_uint8_t
*
)(
de
+
1
))
+
de
->
len
-
1
+
(
data
->
hasftype
?
1
:
0
);
}
static
struct
grub_xfs_dir_entry
*
grub_xfs_inline_next_de
(
struct
grub_xfs_data
*
data
,
struct
grub_xfs_dir_header
*
head
,
struct
grub_xfs_dir_entry
*
de
)
{
char
*
p
=
(
char
*
)
de
+
sizeof
(
struct
grub_xfs_dir_entry
)
-
1
+
de
->
len
;
p
+=
head
->
largeino
?
sizeof
(
grub_uint64_t
)
:
sizeof
(
grub_uint32_t
);
if
(
data
->
hasftype
)
p
++
;
return
(
struct
grub_xfs_dir_entry
*
)
p
;
}
static
struct
grub_xfs_dirblock_tail
*
grub_xfs_dir_tail
(
struct
grub_xfs_data
*
data
,
void
*
dirblock
)
{
int
dirblksize
=
1
<<
(
data
->
sblock
.
log2_bsize
+
data
->
sblock
.
log2_dirblk
);
return
(
struct
grub_xfs_dirblock_tail
*
)
((
char
*
)
dirblock
+
dirblksize
-
sizeof
(
struct
grub_xfs_dirblock_tail
));
}
static
struct
grub_xfs_dir2_entry
*
grub_xfs_first_de
(
struct
grub_xfs_data
*
data
,
void
*
dirblock
)
{
if
(
data
->
hascrc
)
return
(
struct
grub_xfs_dir2_entry
*
)((
char
*
)
dirblock
+
64
);
return
(
struct
grub_xfs_dir2_entry
*
)((
char
*
)
dirblock
+
16
);
}
static
struct
grub_xfs_dir2_entry
*
grub_xfs_next_de
(
struct
grub_xfs_data
*
data
,
struct
grub_xfs_dir2_entry
*
de
)
{
int
size
=
sizeof
(
struct
grub_xfs_dir2_entry
)
+
de
->
len
+
2
/* Tag */
;
if
(
data
->
hasftype
)
size
++
;
/* File type */
return
(
struct
grub_xfs_dir2_entry
*
)(((
char
*
)
de
)
+
ALIGN_UP
(
size
,
8
));
}
/* This should return void * but XFS code is error-prone with alignment, so
return char to retain cast-align.
*/
static
char
*
grub_xfs_btree_keys
(
struct
grub_xfs_data
*
data
,
struct
grub_xfs_btree_node
*
leaf
)
{
char
*
keys
=
(
char
*
)(
leaf
+
1
);
if
(
data
->
hascrc
)
keys
+=
48
;
/* skip crc, uuid, ... */
return
keys
;
}
static
grub_err_t
grub_xfs_read_inode
(
struct
grub_xfs_data
*
data
,
grub_uint64_t
ino
,
struct
grub_xfs_inode
*
inode
)
{
grub_uint64_t
block
=
grub_xfs_inode_block
(
data
,
ino
);
int
offset
=
grub_xfs_inode_offset
(
data
,
ino
);
grub_dprintf
(
"xfs"
,
"Reading inode (%"
PRIuGRUB_UINT64_T
") - %"
PRIuGRUB_UINT64_T
", %d
\n
"
,
ino
,
block
,
offset
);
/* Read the inode. */
if
(
grub_disk_read
(
data
->
disk
,
block
,
offset
,
grub_xfs_inode_size
(
data
),
inode
))
return
grub_errno
;
if
(
grub_strncmp
((
char
*
)
inode
->
magic
,
"IN"
,
2
))
return
grub_error
(
GRUB_ERR_BAD_FS
,
"not a correct XFS inode"
);
return
0
;
}
static
grub_uint64_t
get_fsb
(
const
void
*
keys
,
int
idx
)
{
const
char
*
p
=
(
const
char
*
)
keys
+
sizeof
(
grub_uint64_t
)
*
idx
;
return
grub_be_to_cpu64
(
grub_get_unaligned64
(
p
));
}
static
grub_disk_addr_t
grub_xfs_read_block
(
grub_fshelp_node_t
node
,
grub_disk_addr_t
fileblock
)
{
struct
grub_xfs_btree_node
*
leaf
=
0
;
int
ex
,
nrec
;
struct
grub_xfs_extent
*
exts
;
grub_uint64_t
ret
=
0
;
if
(
node
->
inode
.
format
==
XFS_INODE_FORMAT_BTREE
)
{
struct
grub_xfs_btree_root
*
root
;
const
char
*
keys
;
int
recoffset
;
leaf
=
grub_malloc
(
node
->
data
->
bsize
);
if
(
leaf
==
0
)
return
0
;
root
=
(
struct
grub_xfs_btree_root
*
)
grub_xfs_inode_data
(
&
node
->
inode
);
nrec
=
grub_be_to_cpu16
(
root
->
numrecs
);
keys
=
(
char
*
)
&
root
->
keys
[
0
];
if
(
node
->
inode
.
fork_offset
)
recoffset
=
(
node
->
inode
.
fork_offset
-
1
)
/
2
;
else
recoffset
=
(
grub_xfs_inode_size
(
node
->
data
)
-
((
char
*
)
keys
-
(
char
*
)
&
node
->
inode
))
/
(
2
*
sizeof
(
grub_uint64_t
));
do
{
int
i
;
for
(
i
=
0
;
i
<
nrec
;
i
++
)
{
if
(
fileblock
<
get_fsb
(
keys
,
i
))
break
;
}
/* Sparse block. */
if
(
i
==
0
)
{
grub_free
(
leaf
);
return
0
;
}
if
(
grub_disk_read
(
node
->
data
->
disk
,
GRUB_XFS_FSB_TO_BLOCK
(
node
->
data
,
get_fsb
(
keys
,
i
-
1
+
recoffset
))
<<
(
node
->
data
->
sblock
.
log2_bsize
-
GRUB_DISK_SECTOR_BITS
),
0
,
node
->
data
->
bsize
,
leaf
))
return
0
;
if
((
!
node
->
data
->
hascrc
&&
grub_strncmp
((
char
*
)
leaf
->
magic
,
"BMAP"
,
4
))
||
(
node
->
data
->
hascrc
&&
grub_strncmp
((
char
*
)
leaf
->
magic
,
"BMA3"
,
4
)))
{
grub_free
(
leaf
);
grub_error
(
GRUB_ERR_BAD_FS
,
"not a correct XFS BMAP node"
);
return
0
;
}
nrec
=
grub_be_to_cpu16
(
leaf
->
numrecs
);
keys
=
grub_xfs_btree_keys
(
node
->
data
,
leaf
);
recoffset
=
((
node
->
data
->
bsize
-
((
char
*
)
keys
-
(
char
*
)
leaf
))
/
(
2
*
sizeof
(
grub_uint64_t
)));
}
while
(
leaf
->
level
);
exts
=
(
struct
grub_xfs_extent
*
)
keys
;
}
else
if
(
node
->
inode
.
format
==
XFS_INODE_FORMAT_EXT
)
{
nrec
=
grub_be_to_cpu32
(
node
->
inode
.
nextents
);
exts
=
(
struct
grub_xfs_extent
*
)
grub_xfs_inode_data
(
&
node
->
inode
);
}
else
{
grub_error
(
GRUB_ERR_NOT_IMPLEMENTED_YET
,
"XFS does not support inode format %d yet"
,
node
->
inode
.
format
);
return
0
;
}
/* Iterate over each extent to figure out which extent has
the block we are looking for. */
for
(
ex
=
0
;
ex
<
nrec
;
ex
++
)
{
grub_uint64_t
start
=
GRUB_XFS_EXTENT_BLOCK
(
exts
,
ex
);
grub_uint64_t
offset
=
GRUB_XFS_EXTENT_OFFSET
(
exts
,
ex
);
grub_uint64_t
size
=
GRUB_XFS_EXTENT_SIZE
(
exts
,
ex
);
/* Sparse block. */
if
(
fileblock
<
offset
)
break
;
else
if
(
fileblock
<
offset
+
size
)
{
ret
=
(
fileblock
-
offset
+
start
);
break
;
}
}
grub_free
(
leaf
);
return
GRUB_XFS_FSB_TO_BLOCK
(
node
->
data
,
ret
);
}
/* Read LEN bytes from the file described by DATA starting with byte
POS. Return the amount of read bytes in READ. */
static
grub_ssize_t
grub_xfs_read_file
(
grub_fshelp_node_t
node
,
grub_disk_read_hook_t
read_hook
,
void
*
read_hook_data
,
grub_off_t
pos
,
grub_size_t
len
,
char
*
buf
,
grub_uint32_t
header_size
)
{
return
grub_fshelp_read_file
(
node
->
data
->
disk
,
node
,
read_hook
,
read_hook_data
,
pos
,
len
,
buf
,
grub_xfs_read_block
,
grub_be_to_cpu64
(
node
->
inode
.
size
)
+
header_size
,
node
->
data
->
sblock
.
log2_bsize
-
GRUB_DISK_SECTOR_BITS
,
0
);
}
static
char
*
grub_xfs_read_symlink
(
grub_fshelp_node_t
node
)
{
grub_ssize_t
size
=
grub_be_to_cpu64
(
node
->
inode
.
size
);
if
(
size
<
0
)
{
grub_error
(
GRUB_ERR_BAD_FS
,
"invalid symlink"
);
return
0
;
}
switch
(
node
->
inode
.
format
)
{
case
XFS_INODE_FORMAT_INO
:
return
grub_strndup
(
grub_xfs_inode_data
(
&
node
->
inode
),
size
);
case
XFS_INODE_FORMAT_EXT
:
{
char
*
symlink
;
grub_ssize_t
numread
;
int
off
=
0
;
if
(
node
->
data
->
hascrc
)
off
=
56
;
symlink
=
grub_malloc
(
size
+
1
);
if
(
!
symlink
)
return
0
;
node
->
inode
.
size
=
grub_be_to_cpu64
(
size
+
off
);
numread
=
grub_xfs_read_file
(
node
,
0
,
0
,
off
,
size
,
symlink
,
off
);
if
(
numread
!=
size
)
{
grub_free
(
symlink
);
return
0
;
}
symlink
[
size
]
=
'\0'
;
return
symlink
;
}
}
return
0
;
}
static
enum
grub_fshelp_filetype
grub_xfs_mode_to_filetype
(
grub_uint16_t
mode
)
{
if
((
grub_be_to_cpu16
(
mode
)
&
FILETYPE_INO_MASK
)
==
FILETYPE_INO_DIRECTORY
)
return
GRUB_FSHELP_DIR
;
else
if
((
grub_be_to_cpu16
(
mode
)
&
FILETYPE_INO_MASK
)
==
FILETYPE_INO_SYMLINK
)
return
GRUB_FSHELP_SYMLINK
;
else
if
((
grub_be_to_cpu16
(
mode
)
&
FILETYPE_INO_MASK
)
==
FILETYPE_INO_REG
)
return
GRUB_FSHELP_REG
;
return
GRUB_FSHELP_UNKNOWN
;
}
/* Context for grub_xfs_iterate_dir. */
struct
grub_xfs_iterate_dir_ctx
{
grub_fshelp_iterate_dir_hook_t
hook
;
void
*
hook_data
;
struct
grub_fshelp_node
*
diro
;
};
/* Helper for grub_xfs_iterate_dir. */
static
int
iterate_dir_call_hook
(
grub_uint64_t
ino
,
const
char
*
filename
,
struct
grub_xfs_iterate_dir_ctx
*
ctx
)
{
struct
grub_fshelp_node
*
fdiro
;
grub_err_t
err
;
fdiro
=
grub_malloc
(
grub_xfs_fshelp_size
(
ctx
->
diro
->
data
)
+
1
);
if
(
!
fdiro
)
{
grub_print_error
();
return
0
;
}
/* The inode should be read, otherwise the filetype can
not be determined. */
fdiro
->
ino
=
ino
;
fdiro
->
inode_read
=
1
;
fdiro
->
data
=
ctx
->
diro
->
data
;
err
=
grub_xfs_read_inode
(
ctx
->
diro
->
data
,
ino
,
&
fdiro
->
inode
);
if
(
err
)
{
grub_print_error
();
return
0
;
}
return
ctx
->
hook
(
filename
,
grub_xfs_mode_to_filetype
(
fdiro
->
inode
.
mode
),
fdiro
,
ctx
->
hook_data
);
}
static
int
grub_xfs_iterate_dir
(
grub_fshelp_node_t
dir
,
grub_fshelp_iterate_dir_hook_t
hook
,
void
*
hook_data
)
{
struct
grub_fshelp_node
*
diro
=
(
struct
grub_fshelp_node
*
)
dir
;
struct
grub_xfs_iterate_dir_ctx
ctx
=
{
.
hook
=
hook
,
.
hook_data
=
hook_data
,
.
diro
=
diro
};
switch
(
diro
->
inode
.
format
)
{
case
XFS_INODE_FORMAT_INO
:
{
struct
grub_xfs_dir_header
*
head
=
(
struct
grub_xfs_dir_header
*
)
grub_xfs_inode_data
(
&
diro
->
inode
);
struct
grub_xfs_dir_entry
*
de
=
grub_xfs_inline_de
(
head
);
int
smallino
=
!
head
->
largeino
;
int
i
;
grub_uint64_t
parent
;
/* If small inode numbers are used to pack the direntry, the
parent inode number is small too. */
if
(
smallino
)
parent
=
grub_be_to_cpu32
(
head
->
parent
.
i4
);
else
parent
=
grub_be_to_cpu64
(
head
->
parent
.
i8
);
/* Synthesize the direntries for `.' and `..'. */
if
(
iterate_dir_call_hook
(
diro
->
ino
,
"."
,
&
ctx
))
return
1
;
if
(
iterate_dir_call_hook
(
parent
,
".."
,
&
ctx
))
return
1
;
for
(
i
=
0
;
i
<
head
->
count
;
i
++
)
{
grub_uint64_t
ino
;
grub_uint8_t
*
inopos
=
grub_xfs_inline_de_inopos
(
dir
->
data
,
de
);
grub_uint8_t
c
;
/* inopos might be unaligned. */
if
(
smallino
)
ino
=
(((
grub_uint32_t
)
inopos
[
0
])
<<
24
)
|
(((
grub_uint32_t
)
inopos
[
1
])
<<
16
)
|
(((
grub_uint32_t
)
inopos
[
2
])
<<
8
)
|
(((
grub_uint32_t
)
inopos
[
3
])
<<
0
);
else
ino
=
(((
grub_uint64_t
)
inopos
[
0
])
<<
56
)
|
(((
grub_uint64_t
)
inopos
[
1
])
<<
48
)
|
(((
grub_uint64_t
)
inopos
[
2
])
<<
40
)
|
(((
grub_uint64_t
)
inopos
[
3
])
<<
32
)
|
(((
grub_uint64_t
)
inopos
[
4
])
<<
24
)
|
(((
grub_uint64_t
)
inopos
[
5
])
<<
16
)
|
(((
grub_uint64_t
)
inopos
[
6
])
<<
8
)
|
(((
grub_uint64_t
)
inopos
[
7
])
<<
0
);
c
=
de
->
name
[
de
->
len
];
de
->
name
[
de
->
len
]
=
'\0'
;
if
(
iterate_dir_call_hook
(
ino
,
de
->
name
,
&
ctx
))
{
de
->
name
[
de
->
len
]
=
c
;
return
1
;
}
de
->
name
[
de
->
len
]
=
c
;
de
=
grub_xfs_inline_next_de
(
dir
->
data
,
head
,
de
);
}
break
;
}
case
XFS_INODE_FORMAT_BTREE
:
case
XFS_INODE_FORMAT_EXT
:
{
grub_ssize_t
numread
;
char
*
dirblock
;
grub_uint64_t
blk
;
int
dirblk_size
,
dirblk_log2
;
dirblk_log2
=
(
dir
->
data
->
sblock
.
log2_bsize
+
dir
->
data
->
sblock
.
log2_dirblk
);
dirblk_size
=
1
<<
dirblk_log2
;
dirblock
=
grub_malloc
(
dirblk_size
);
if
(
!
dirblock
)
return
0
;
/* Iterate over every block the directory has. */
for
(
blk
=
0
;
blk
<
(
grub_be_to_cpu64
(
dir
->
inode
.
size
)
>>
dirblk_log2
);
blk
++
)
{
struct
grub_xfs_dir2_entry
*
direntry
=
grub_xfs_first_de
(
dir
->
data
,
dirblock
);
int
entries
;
struct
grub_xfs_dirblock_tail
*
tail
=
grub_xfs_dir_tail
(
dir
->
data
,
dirblock
);
numread
=
grub_xfs_read_file
(
dir
,
0
,
0
,
blk
<<
dirblk_log2
,
dirblk_size
,
dirblock
,
0
);
if
(
numread
!=
dirblk_size
)
return
0
;
entries
=
(
grub_be_to_cpu32
(
tail
->
leaf_count
)
-
grub_be_to_cpu32
(
tail
->
leaf_stale
));
if
(
!
entries
)
continue
;
/* Iterate over all entries within this block. */
while
((
char
*
)
direntry
<
(
char
*
)
tail
)
{
grub_uint8_t
*
freetag
;
char
*
filename
;
freetag
=
(
grub_uint8_t
*
)
direntry
;
if
(
grub_get_unaligned16
(
freetag
)
==
0XFFFF
)
{
grub_uint8_t
*
skip
=
(
freetag
+
sizeof
(
grub_uint16_t
));
/* This entry is not used, go to the next one. */
direntry
=
(
struct
grub_xfs_dir2_entry
*
)
(((
char
*
)
direntry
)
+
grub_be_to_cpu16
(
grub_get_unaligned16
(
skip
)));
continue
;
}
filename
=
(
char
*
)(
direntry
+
1
);
/* The byte after the filename is for the filetype, padding, or
tag, which is not used by GRUB. So it can be overwritten. */
filename
[
direntry
->
len
]
=
'\0'
;
if
(
iterate_dir_call_hook
(
grub_be_to_cpu64
(
direntry
->
inode
),
filename
,
&
ctx
))
{
grub_free
(
dirblock
);
return
1
;
}
/* Check if last direntry in this block is
reached. */
entries
--
;
if
(
!
entries
)
break
;
/* Select the next directory entry. */
direntry
=
grub_xfs_next_de
(
dir
->
data
,
direntry
);
}
}
grub_free
(
dirblock
);
break
;
}
default:
grub_error
(
GRUB_ERR_NOT_IMPLEMENTED_YET
,
"XFS does not support inode format %d yet"
,
diro
->
inode
.
format
);
}
return
0
;
}
static
struct
grub_xfs_data
*
grub_xfs_mount
(
grub_disk_t
disk
)
{
struct
grub_xfs_data
*
data
=
0
;
data
=
grub_zalloc
(
sizeof
(
struct
grub_xfs_data
));
if
(
!
data
)
return
0
;
grub_dprintf
(
"xfs"
,
"Reading sb
\n
"
);
/* Read the superblock. */
if
(
grub_disk_read
(
disk
,
0
,
0
,
sizeof
(
struct
grub_xfs_sblock
),
&
data
->
sblock
))
goto
fail
;
if
(
!
grub_xfs_sb_valid
(
data
))
goto
fail
;
data
=
grub_realloc
(
data
,
sizeof
(
struct
grub_xfs_data
)
-
sizeof
(
struct
grub_xfs_inode
)
+
grub_xfs_inode_size
(
data
)
+
1
);
if
(
!
data
)
goto
fail
;
data
->
diropen
.
data
=
data
;
data
->
diropen
.
ino
=
grub_be_to_cpu64
(
data
->
sblock
.
rootino
);
data
->
diropen
.
inode_read
=
1
;
data
->
bsize
=
grub_be_to_cpu32
(
data
->
sblock
.
bsize
);
data
->
agsize
=
grub_be_to_cpu32
(
data
->
sblock
.
agsize
);
data
->
hasftype
=
grub_xfs_sb_hasftype
(
data
);
data
->
hascrc
=
grub_xfs_sb_hascrc
(
data
);
data
->
disk
=
disk
;
data
->
pos
=
0
;
grub_dprintf
(
"xfs"
,
"Reading root ino %"
PRIuGRUB_UINT64_T
"
\n
"
,
grub_cpu_to_be64
(
data
->
sblock
.
rootino
));
grub_xfs_read_inode
(
data
,
data
->
diropen
.
ino
,
&
data
->
diropen
.
inode
);
return
data
;
fail:
if
(
grub_errno
==
GRUB_ERR_OUT_OF_RANGE
)
grub_error
(
GRUB_ERR_BAD_FS
,
"not an XFS filesystem"
);
grub_free
(
data
);
return
0
;
}
/* Context for grub_xfs_dir. */
struct
grub_xfs_dir_ctx
{
grub_fs_dir_hook_t
hook
;
void
*
hook_data
;
};
/* Helper for grub_xfs_dir. */
static
int
grub_xfs_dir_iter
(
const
char
*
filename
,
enum
grub_fshelp_filetype
filetype
,
grub_fshelp_node_t
node
,
void
*
data
)
{
struct
grub_xfs_dir_ctx
*
ctx
=
data
;
struct
grub_dirhook_info
info
;
grub_memset
(
&
info
,
0
,
sizeof
(
info
));
if
(
node
->
inode_read
)
{
info
.
mtimeset
=
1
;
info
.
mtime
=
grub_be_to_cpu32
(
node
->
inode
.
mtime
.
sec
);
}
info
.
dir
=
((
filetype
&
GRUB_FSHELP_TYPE_MASK
)
==
GRUB_FSHELP_DIR
);
if
(
!
info
.
dir
)
info
.
size
=
node
->
inode
.
size
;
grub_free
(
node
);
return
ctx
->
hook
(
filename
,
&
info
,
ctx
->
hook_data
);
}
static
grub_err_t
grub_xfs_dir
(
grub_device_t
device
,
const
char
*
path
,
grub_fs_dir_hook_t
hook
,
void
*
hook_data
)
{
struct
grub_xfs_dir_ctx
ctx
=
{
hook
,
hook_data
};
struct
grub_xfs_data
*
data
=
0
;
struct
grub_fshelp_node
*
fdiro
=
0
;
grub_dl_ref
(
my_mod
);
data
=
grub_xfs_mount
(
device
->
disk
);
if
(
!
data
)
goto
mount_fail
;
grub_fshelp_find_file
(
path
,
&
data
->
diropen
,
&
fdiro
,
grub_xfs_iterate_dir
,
grub_xfs_read_symlink
,
GRUB_FSHELP_DIR
);
if
(
grub_errno
)
goto
fail
;
grub_xfs_iterate_dir
(
fdiro
,
grub_xfs_dir_iter
,
&
ctx
);
fail:
if
(
fdiro
!=
&
data
->
diropen
)
grub_free
(
fdiro
);
grub_free
(
data
);
mount_fail:
grub_dl_unref
(
my_mod
);
return
grub_errno
;
}
/* Open a file named NAME and initialize FILE. */
static
grub_err_t
grub_xfs_open
(
struct
grub_file
*
file
,
const
char
*
name
)
{
struct
grub_xfs_data
*
data
;
struct
grub_fshelp_node
*
fdiro
=
0
;
grub_dl_ref
(
my_mod
);
data
=
grub_xfs_mount
(
file
->
device
->
disk
);
if
(
!
data
)
goto
mount_fail
;
grub_fshelp_find_file
(
name
,
&
data
->
diropen
,
&
fdiro
,
grub_xfs_iterate_dir
,
grub_xfs_read_symlink
,
GRUB_FSHELP_REG
);
if
(
grub_errno
)
goto
fail
;
if
(
!
fdiro
->
inode_read
)
{
grub_xfs_read_inode
(
data
,
fdiro
->
ino
,
&
fdiro
->
inode
);
if
(
grub_errno
)
goto
fail
;
}
if
(
fdiro
!=
&
data
->
diropen
)
{
grub_memcpy
(
&
data
->
diropen
,
fdiro
,
grub_xfs_fshelp_size
(
data
));
grub_free
(
fdiro
);
}
file
->
size
=
grub_be_to_cpu64
(
data
->
diropen
.
inode
.
size
);
file
->
data
=
data
;
file
->
offset
=
0
;
return
0
;
fail:
if
(
fdiro
!=
&
data
->
diropen
)
grub_free
(
fdiro
);
grub_free
(
data
);
mount_fail:
grub_dl_unref
(
my_mod
);
return
grub_errno
;
}
static
grub_ssize_t
grub_xfs_read
(
grub_file_t
file
,
char
*
buf
,
grub_size_t
len
)
{
struct
grub_xfs_data
*
data
=
(
struct
grub_xfs_data
*
)
file
->
data
;
return
grub_xfs_read_file
(
&
data
->
diropen
,
file
->
read_hook
,
file
->
read_hook_data
,
file
->
offset
,
len
,
buf
,
0
);
}
static
grub_err_t
grub_xfs_close
(
grub_file_t
file
)
{
grub_free
(
file
->
data
);
grub_dl_unref
(
my_mod
);
return
GRUB_ERR_NONE
;
}
static
grub_err_t
grub_xfs_label
(
grub_device_t
device
,
char
**
label
)
{
struct
grub_xfs_data
*
data
;
grub_disk_t
disk
=
device
->
disk
;
grub_dl_ref
(
my_mod
);
data
=
grub_xfs_mount
(
disk
);
if
(
data
)
*
label
=
grub_strndup
((
char
*
)
(
data
->
sblock
.
label
),
12
);
else
*
label
=
0
;
grub_dl_unref
(
my_mod
);
grub_free
(
data
);
return
grub_errno
;
}
static
grub_err_t
grub_xfs_uuid
(
grub_device_t
device
,
char
**
uuid
)
{
struct
grub_xfs_data
*
data
;
grub_disk_t
disk
=
device
->
disk
;
grub_dl_ref
(
my_mod
);
data
=
grub_xfs_mount
(
disk
);
if
(
data
)
{
*
uuid
=
grub_xasprintf
(
"%04x%04x-%04x-%04x-%04x-%04x%04x%04x"
,
grub_be_to_cpu16
(
data
->
sblock
.
uuid
[
0
]),
grub_be_to_cpu16
(
data
->
sblock
.
uuid
[
1
]),
grub_be_to_cpu16
(
data
->
sblock
.
uuid
[
2
]),
grub_be_to_cpu16
(
data
->
sblock
.
uuid
[
3
]),
grub_be_to_cpu16
(
data
->
sblock
.
uuid
[
4
]),
grub_be_to_cpu16
(
data
->
sblock
.
uuid
[
5
]),
grub_be_to_cpu16
(
data
->
sblock
.
uuid
[
6
]),
grub_be_to_cpu16
(
data
->
sblock
.
uuid
[
7
]));
}
else
*
uuid
=
NULL
;
grub_dl_unref
(
my_mod
);
grub_free
(
data
);
return
grub_errno
;
}
static
struct
grub_fs
grub_xfs_fs
=
{
.
name
=
"xfs"
,
.
fs_dir
=
grub_xfs_dir
,
.
fs_open
=
grub_xfs_open
,
.
fs_read
=
grub_xfs_read
,
.
fs_close
=
grub_xfs_close
,
.
fs_label
=
grub_xfs_label
,
.
fs_uuid
=
grub_xfs_uuid
,
#ifdef GRUB_UTIL
.
reserved_first_sector
=
0
,
.
blocklist_install
=
1
,
#endif
.
next
=
0
};
GRUB_MOD_INIT
(
xfs
)
{
grub_fs_register
(
&
grub_xfs_fs
);
my_mod
=
mod
;
}
GRUB_MOD_FINI
(
xfs
)
{
grub_fs_unregister
(
&
grub_xfs_fs
);
}
GRUB2/grub-2.04/grub-core/kern/disk.c
0 → 100644
View file @
84c50066
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2002,2003,2004,2006,2007,2008,2009,2010 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <grub/disk.h>
#include <grub/err.h>
#include <grub/mm.h>
#include <grub/types.h>
#include <grub/partition.h>
#include <grub/misc.h>
#include <grub/time.h>
#include <grub/file.h>
#include <grub/i18n.h>
#include <grub/ventoy.h>
#define GRUB_CACHE_TIMEOUT 2
/* The last time the disk was used. */
static
grub_uint64_t
grub_last_time
=
0
;
struct
grub_disk_cache
grub_disk_cache_table
[
GRUB_DISK_CACHE_NUM
];
void
(
*
grub_disk_firmware_fini
)
(
void
);
int
grub_disk_firmware_is_tainted
;
#if DISK_CACHE_STATS
static
unsigned
long
grub_disk_cache_hits
;
static
unsigned
long
grub_disk_cache_misses
;
void
grub_disk_cache_get_performance
(
unsigned
long
*
hits
,
unsigned
long
*
misses
)
{
*
hits
=
grub_disk_cache_hits
;
*
misses
=
grub_disk_cache_misses
;
}
#endif
grub_err_t
(
*
grub_disk_write_weak
)
(
grub_disk_t
disk
,
grub_disk_addr_t
sector
,
grub_off_t
offset
,
grub_size_t
size
,
const
void
*
buf
);
#include "disk_common.c"
void
grub_disk_cache_invalidate_all
(
void
)
{
unsigned
i
;
for
(
i
=
0
;
i
<
GRUB_DISK_CACHE_NUM
;
i
++
)
{
struct
grub_disk_cache
*
cache
=
grub_disk_cache_table
+
i
;
if
(
cache
->
data
&&
!
cache
->
lock
)
{
grub_free
(
cache
->
data
);
cache
->
data
=
0
;
}
}
}
static
char
*
grub_disk_cache_fetch
(
unsigned
long
dev_id
,
unsigned
long
disk_id
,
grub_disk_addr_t
sector
)
{
struct
grub_disk_cache
*
cache
;
unsigned
cache_index
;
cache_index
=
grub_disk_cache_get_index
(
dev_id
,
disk_id
,
sector
);
cache
=
grub_disk_cache_table
+
cache_index
;
if
(
cache
->
dev_id
==
dev_id
&&
cache
->
disk_id
==
disk_id
&&
cache
->
sector
==
sector
)
{
cache
->
lock
=
1
;
#if DISK_CACHE_STATS
grub_disk_cache_hits
++
;
#endif
return
cache
->
data
;
}
#if DISK_CACHE_STATS
grub_disk_cache_misses
++
;
#endif
return
0
;
}
static
void
grub_disk_cache_unlock
(
unsigned
long
dev_id
,
unsigned
long
disk_id
,
grub_disk_addr_t
sector
)
{
struct
grub_disk_cache
*
cache
;
unsigned
cache_index
;
cache_index
=
grub_disk_cache_get_index
(
dev_id
,
disk_id
,
sector
);
cache
=
grub_disk_cache_table
+
cache_index
;
if
(
cache
->
dev_id
==
dev_id
&&
cache
->
disk_id
==
disk_id
&&
cache
->
sector
==
sector
)
cache
->
lock
=
0
;
}
static
grub_err_t
grub_disk_cache_store
(
unsigned
long
dev_id
,
unsigned
long
disk_id
,
grub_disk_addr_t
sector
,
const
char
*
data
)
{
unsigned
cache_index
;
struct
grub_disk_cache
*
cache
;
cache_index
=
grub_disk_cache_get_index
(
dev_id
,
disk_id
,
sector
);
cache
=
grub_disk_cache_table
+
cache_index
;
cache
->
lock
=
1
;
grub_free
(
cache
->
data
);
cache
->
data
=
0
;
cache
->
lock
=
0
;
cache
->
data
=
grub_malloc
(
GRUB_DISK_SECTOR_SIZE
<<
GRUB_DISK_CACHE_BITS
);
if
(
!
cache
->
data
)
return
grub_errno
;
grub_memcpy
(
cache
->
data
,
data
,
GRUB_DISK_SECTOR_SIZE
<<
GRUB_DISK_CACHE_BITS
);
cache
->
dev_id
=
dev_id
;
cache
->
disk_id
=
disk_id
;
cache
->
sector
=
sector
;
return
GRUB_ERR_NONE
;
}
grub_disk_dev_t
grub_disk_dev_list
;
void
grub_disk_dev_register
(
grub_disk_dev_t
dev
)
{
dev
->
next
=
grub_disk_dev_list
;
grub_disk_dev_list
=
dev
;
}
void
grub_disk_dev_unregister
(
grub_disk_dev_t
dev
)
{
grub_disk_dev_t
*
p
,
q
;
for
(
p
=
&
grub_disk_dev_list
,
q
=
*
p
;
q
;
p
=
&
(
q
->
next
),
q
=
q
->
next
)
if
(
q
==
dev
)
{
*
p
=
q
->
next
;
break
;
}
}
/* Return the location of the first ',', if any, which is not
escaped by a '\'. */
static
const
char
*
find_part_sep
(
const
char
*
name
)
{
const
char
*
p
=
name
;
char
c
;
while
((
c
=
*
p
++
)
!=
'\0'
)
{
if
(
c
==
'\\'
&&
*
p
==
','
)
p
++
;
else
if
(
c
==
','
)
return
p
-
1
;
}
return
NULL
;
}
grub_disk_t
grub_disk_open
(
const
char
*
name
)
{
const
char
*
p
;
grub_disk_t
disk
;
grub_disk_dev_t
dev
;
char
*
raw
=
(
char
*
)
name
;
grub_uint64_t
current_time
;
grub_dprintf
(
"disk"
,
"Opening `%s'...
\n
"
,
name
);
disk
=
(
grub_disk_t
)
grub_zalloc
(
sizeof
(
*
disk
));
if
(
!
disk
)
return
0
;
disk
->
log_sector_size
=
GRUB_DISK_SECTOR_BITS
;
/* Default 1MiB of maximum agglomerate. */
disk
->
max_agglomerate
=
1048576
>>
(
GRUB_DISK_SECTOR_BITS
+
GRUB_DISK_CACHE_BITS
);
p
=
find_part_sep
(
name
);
if
(
p
)
{
grub_size_t
len
=
p
-
name
;
raw
=
grub_malloc
(
len
+
1
);
if
(
!
raw
)
goto
fail
;
grub_memcpy
(
raw
,
name
,
len
);
raw
[
len
]
=
'\0'
;
disk
->
name
=
grub_strdup
(
raw
);
}
else
disk
->
name
=
grub_strdup
(
name
);
if
(
!
disk
->
name
)
goto
fail
;
for
(
dev
=
grub_disk_dev_list
;
dev
;
dev
=
dev
->
next
)
{
if
((
dev
->
disk_open
)
(
raw
,
disk
)
==
GRUB_ERR_NONE
)
break
;
else
if
(
grub_errno
==
GRUB_ERR_UNKNOWN_DEVICE
)
grub_errno
=
GRUB_ERR_NONE
;
else
goto
fail
;
}
if
(
!
dev
)
{
grub_error
(
GRUB_ERR_UNKNOWN_DEVICE
,
N_
(
"disk `%s' not found"
),
name
);
goto
fail
;
}
if
(
disk
->
log_sector_size
>
GRUB_DISK_CACHE_BITS
+
GRUB_DISK_SECTOR_BITS
||
disk
->
log_sector_size
<
GRUB_DISK_SECTOR_BITS
)
{
grub_error
(
GRUB_ERR_NOT_IMPLEMENTED_YET
,
"sector sizes of %d bytes aren't supported yet"
,
(
1
<<
disk
->
log_sector_size
));
goto
fail
;
}
disk
->
dev
=
dev
;
if
(
p
)
{
disk
->
partition
=
grub_partition_probe
(
disk
,
p
+
1
);
if
(
!
disk
->
partition
)
{
/* TRANSLATORS: It means that the specified partition e.g.
hd0,msdos1=/dev/sda1 doesn't exist. */
grub_error
(
GRUB_ERR_UNKNOWN_DEVICE
,
N_
(
"no such partition"
));
goto
fail
;
}
}
/* The cache will be invalidated about 2 seconds after a device was
closed. */
current_time
=
grub_get_time_ms
();
if
(
current_time
>
(
grub_last_time
+
GRUB_CACHE_TIMEOUT
*
1000
))
grub_disk_cache_invalidate_all
();
grub_last_time
=
current_time
;
fail:
if
(
raw
&&
raw
!=
name
)
grub_free
(
raw
);
if
(
grub_errno
!=
GRUB_ERR_NONE
)
{
grub_error_push
();
grub_dprintf
(
"disk"
,
"Opening `%s' failed.
\n
"
,
name
);
grub_error_pop
();
grub_disk_close
(
disk
);
return
0
;
}
return
disk
;
}
void
grub_disk_close
(
grub_disk_t
disk
)
{
grub_partition_t
part
;
grub_dprintf
(
"disk"
,
"Closing `%s'.
\n
"
,
disk
->
name
);
if
(
disk
->
dev
&&
disk
->
dev
->
disk_close
)
(
disk
->
dev
->
disk_close
)
(
disk
);
/* Reset the timer. */
grub_last_time
=
grub_get_time_ms
();
while
(
disk
->
partition
)
{
part
=
disk
->
partition
->
parent
;
grub_free
(
disk
->
partition
);
disk
->
partition
=
part
;
}
grub_free
((
void
*
)
disk
->
name
);
grub_free
(
disk
);
}
/* Small read (less than cache size and not pass across cache unit boundaries).
sector is already adjusted and is divisible by cache unit size.
*/
static
grub_err_t
grub_disk_read_small_real
(
grub_disk_t
disk
,
grub_disk_addr_t
sector
,
grub_off_t
offset
,
grub_size_t
size
,
void
*
buf
)
{
char
*
data
;
char
*
tmp_buf
;
/* Fetch the cache. */
data
=
grub_disk_cache_fetch
(
disk
->
dev
->
id
,
disk
->
id
,
sector
);
if
(
data
)
{
/* Just copy it! */
grub_memcpy
(
buf
,
data
+
offset
,
size
);
grub_disk_cache_unlock
(
disk
->
dev
->
id
,
disk
->
id
,
sector
);
return
GRUB_ERR_NONE
;
}
/* Allocate a temporary buffer. */
tmp_buf
=
grub_malloc
(
GRUB_DISK_SECTOR_SIZE
<<
GRUB_DISK_CACHE_BITS
);
if
(
!
tmp_buf
)
return
grub_errno
;
/* Otherwise read data from the disk actually. */
if
(
disk
->
total_sectors
==
GRUB_DISK_SIZE_UNKNOWN
||
sector
+
GRUB_DISK_CACHE_SIZE
<
(
disk
->
total_sectors
<<
(
disk
->
log_sector_size
-
GRUB_DISK_SECTOR_BITS
)))
{
grub_err_t
err
;
err
=
(
disk
->
dev
->
disk_read
)
(
disk
,
transform_sector
(
disk
,
sector
),
1U
<<
(
GRUB_DISK_CACHE_BITS
+
GRUB_DISK_SECTOR_BITS
-
disk
->
log_sector_size
),
tmp_buf
);
if
(
!
err
)
{
/* Copy it and store it in the disk cache. */
grub_memcpy
(
buf
,
tmp_buf
+
offset
,
size
);
grub_disk_cache_store
(
disk
->
dev
->
id
,
disk
->
id
,
sector
,
tmp_buf
);
grub_free
(
tmp_buf
);
return
GRUB_ERR_NONE
;
}
}
grub_free
(
tmp_buf
);
grub_errno
=
GRUB_ERR_NONE
;
{
/* Uggh... Failed. Instead, just read necessary data. */
unsigned
num
;
grub_disk_addr_t
aligned_sector
;
sector
+=
(
offset
>>
GRUB_DISK_SECTOR_BITS
);
offset
&=
((
1
<<
GRUB_DISK_SECTOR_BITS
)
-
1
);
aligned_sector
=
(
sector
&
~
((
1ULL
<<
(
disk
->
log_sector_size
-
GRUB_DISK_SECTOR_BITS
))
-
1
));
offset
+=
((
sector
-
aligned_sector
)
<<
GRUB_DISK_SECTOR_BITS
);
num
=
((
size
+
offset
+
(
1ULL
<<
(
disk
->
log_sector_size
))
-
1
)
>>
(
disk
->
log_sector_size
));
tmp_buf
=
grub_malloc
(
num
<<
disk
->
log_sector_size
);
if
(
!
tmp_buf
)
return
grub_errno
;
if
((
disk
->
dev
->
disk_read
)
(
disk
,
transform_sector
(
disk
,
aligned_sector
),
num
,
tmp_buf
))
{
grub_error_push
();
grub_dprintf
(
"disk"
,
"%s read failed
\n
"
,
disk
->
name
);
grub_error_pop
();
grub_free
(
tmp_buf
);
return
grub_errno
;
}
grub_memcpy
(
buf
,
tmp_buf
+
offset
,
size
);
grub_free
(
tmp_buf
);
return
GRUB_ERR_NONE
;
}
}
static
grub_err_t
grub_disk_read_small
(
grub_disk_t
disk
,
grub_disk_addr_t
sector
,
grub_off_t
offset
,
grub_size_t
size
,
void
*
buf
)
{
grub_err_t
err
;
err
=
grub_disk_read_small_real
(
disk
,
sector
,
offset
,
size
,
buf
);
if
(
err
)
return
err
;
if
(
disk
->
read_hook
)
(
disk
->
read_hook
)
(
sector
+
(
offset
>>
GRUB_DISK_SECTOR_BITS
),
offset
&
(
GRUB_DISK_SECTOR_SIZE
-
1
),
size
,
disk
->
read_hook_data
);
return
GRUB_ERR_NONE
;
}
grub_err_t
grub_disk_blocklist_read
(
void
*
chunklist
,
grub_uint64_t
sector
,
grub_uint64_t
size
,
grub_uint32_t
log_sector_size
)
{
ventoy_img_chunk
*
last_chunk
=
NULL
;
ventoy_img_chunk
*
new_chunk
=
NULL
;
ventoy_img_chunk_list
*
chunk_list
=
(
ventoy_img_chunk_list
*
)
chunklist
;
if
(
chunk_list
->
cur_chunk
==
0
)
{
chunk_list
->
chunk
[
0
].
img_start_sector
=
0
;
chunk_list
->
chunk
[
0
].
img_end_sector
=
(
size
>>
11
)
-
1
;
chunk_list
->
chunk
[
0
].
disk_start_sector
=
sector
;
chunk_list
->
chunk
[
0
].
disk_end_sector
=
sector
+
(
size
>>
log_sector_size
)
-
1
;
chunk_list
->
cur_chunk
=
1
;
return
0
;
}
last_chunk
=
chunk_list
->
chunk
+
chunk_list
->
cur_chunk
-
1
;
if
(
last_chunk
->
disk_end_sector
+
1
==
sector
)
{
last_chunk
->
img_end_sector
+=
(
size
>>
11
);
last_chunk
->
disk_end_sector
+=
(
size
>>
log_sector_size
);
return
0
;
}
if
(
chunk_list
->
cur_chunk
==
chunk_list
->
max_chunk
)
{
new_chunk
=
grub_realloc
(
chunk_list
->
chunk
,
chunk_list
->
max_chunk
*
2
*
sizeof
(
ventoy_img_chunk
));
if
(
NULL
==
new_chunk
)
{
return
-
1
;
}
chunk_list
->
chunk
=
new_chunk
;
chunk_list
->
max_chunk
*=
2
;
/* issue: update last_chunk */
last_chunk
=
chunk_list
->
chunk
+
chunk_list
->
cur_chunk
-
1
;
}
new_chunk
=
chunk_list
->
chunk
+
chunk_list
->
cur_chunk
;
new_chunk
->
img_start_sector
=
last_chunk
->
img_end_sector
+
1
;
new_chunk
->
img_end_sector
=
new_chunk
->
img_start_sector
+
(
size
>>
11
)
-
1
;
new_chunk
->
disk_start_sector
=
sector
;
new_chunk
->
disk_end_sector
=
sector
+
(
size
>>
log_sector_size
)
-
1
;
chunk_list
->
cur_chunk
++
;
return
0
;
}
/* Read data from the disk. */
grub_err_t
grub_disk_read
(
grub_disk_t
disk
,
grub_disk_addr_t
sector
,
grub_off_t
offset
,
grub_size_t
size
,
void
*
buf
)
{
if
(
disk
->
read_hook
==
(
grub_disk_read_hook_t
)
grub_disk_blocklist_read
)
{
return
grub_disk_blocklist_read
((
ventoy_img_chunk_list
*
)
disk
->
read_hook_data
,
sector
,
size
,
disk
->
log_sector_size
);
}
/* First of all, check if the region is within the disk. */
if
(
grub_disk_adjust_range
(
disk
,
&
sector
,
&
offset
,
size
)
!=
GRUB_ERR_NONE
)
{
grub_error_push
();
grub_dprintf
(
"disk"
,
"Read out of range: sector 0x%llx (%s).
\n
"
,
(
unsigned
long
long
)
sector
,
grub_errmsg
);
grub_error_pop
();
return
grub_errno
;
}
/* First read until first cache boundary. */
if
(
offset
||
(
sector
&
(
GRUB_DISK_CACHE_SIZE
-
1
)))
{
grub_disk_addr_t
start_sector
;
grub_size_t
pos
;
grub_err_t
err
;
grub_size_t
len
;
start_sector
=
sector
&
~
((
grub_disk_addr_t
)
GRUB_DISK_CACHE_SIZE
-
1
);
pos
=
(
sector
-
start_sector
)
<<
GRUB_DISK_SECTOR_BITS
;
len
=
((
GRUB_DISK_SECTOR_SIZE
<<
GRUB_DISK_CACHE_BITS
)
-
pos
-
offset
);
if
(
len
>
size
)
len
=
size
;
err
=
grub_disk_read_small
(
disk
,
start_sector
,
offset
+
pos
,
len
,
buf
);
if
(
err
)
return
err
;
buf
=
(
char
*
)
buf
+
len
;
size
-=
len
;
offset
+=
len
;
sector
+=
(
offset
>>
GRUB_DISK_SECTOR_BITS
);
offset
&=
((
1
<<
GRUB_DISK_SECTOR_BITS
)
-
1
);
}
/* Until SIZE is zero... */
while
(
size
>=
(
GRUB_DISK_CACHE_SIZE
<<
GRUB_DISK_SECTOR_BITS
))
{
char
*
data
=
NULL
;
grub_disk_addr_t
agglomerate
;
grub_err_t
err
;
/* agglomerate read until we find a first cached entry. */
for
(
agglomerate
=
0
;
agglomerate
<
(
size
>>
(
GRUB_DISK_SECTOR_BITS
+
GRUB_DISK_CACHE_BITS
))
&&
agglomerate
<
disk
->
max_agglomerate
;
agglomerate
++
)
{
data
=
grub_disk_cache_fetch
(
disk
->
dev
->
id
,
disk
->
id
,
sector
+
(
agglomerate
<<
GRUB_DISK_CACHE_BITS
));
if
(
data
)
break
;
}
if
(
data
)
{
grub_memcpy
((
char
*
)
buf
+
(
agglomerate
<<
(
GRUB_DISK_CACHE_BITS
+
GRUB_DISK_SECTOR_BITS
)),
data
,
GRUB_DISK_CACHE_SIZE
<<
GRUB_DISK_SECTOR_BITS
);
grub_disk_cache_unlock
(
disk
->
dev
->
id
,
disk
->
id
,
sector
+
(
agglomerate
<<
GRUB_DISK_CACHE_BITS
));
}
if
(
agglomerate
)
{
grub_disk_addr_t
i
;
err
=
(
disk
->
dev
->
disk_read
)
(
disk
,
transform_sector
(
disk
,
sector
),
agglomerate
<<
(
GRUB_DISK_CACHE_BITS
+
GRUB_DISK_SECTOR_BITS
-
disk
->
log_sector_size
),
buf
);
if
(
err
)
return
err
;
for
(
i
=
0
;
i
<
agglomerate
;
i
++
)
grub_disk_cache_store
(
disk
->
dev
->
id
,
disk
->
id
,
sector
+
(
i
<<
GRUB_DISK_CACHE_BITS
),
(
char
*
)
buf
+
(
i
<<
(
GRUB_DISK_CACHE_BITS
+
GRUB_DISK_SECTOR_BITS
)));
if
(
disk
->
read_hook
)
(
disk
->
read_hook
)
(
sector
,
0
,
agglomerate
<<
(
GRUB_DISK_CACHE_BITS
+
GRUB_DISK_SECTOR_BITS
),
disk
->
read_hook_data
);
sector
+=
agglomerate
<<
GRUB_DISK_CACHE_BITS
;
size
-=
agglomerate
<<
(
GRUB_DISK_CACHE_BITS
+
GRUB_DISK_SECTOR_BITS
);
buf
=
(
char
*
)
buf
+
(
agglomerate
<<
(
GRUB_DISK_CACHE_BITS
+
GRUB_DISK_SECTOR_BITS
));
}
if
(
data
)
{
if
(
disk
->
read_hook
)
(
disk
->
read_hook
)
(
sector
,
0
,
(
GRUB_DISK_CACHE_SIZE
<<
GRUB_DISK_SECTOR_BITS
),
disk
->
read_hook_data
);
sector
+=
GRUB_DISK_CACHE_SIZE
;
buf
=
(
char
*
)
buf
+
(
GRUB_DISK_CACHE_SIZE
<<
GRUB_DISK_SECTOR_BITS
);
size
-=
(
GRUB_DISK_CACHE_SIZE
<<
GRUB_DISK_SECTOR_BITS
);
}
}
/* And now read the last part. */
if
(
size
)
{
grub_err_t
err
;
err
=
grub_disk_read_small
(
disk
,
sector
,
0
,
size
,
buf
);
if
(
err
)
return
err
;
}
return
grub_errno
;
}
grub_uint64_t
grub_disk_get_size
(
grub_disk_t
disk
)
{
if
(
disk
->
partition
)
return
grub_partition_get_len
(
disk
->
partition
);
else
if
(
disk
->
total_sectors
!=
GRUB_DISK_SIZE_UNKNOWN
)
return
disk
->
total_sectors
<<
(
disk
->
log_sector_size
-
GRUB_DISK_SECTOR_BITS
);
else
return
GRUB_DISK_SIZE_UNKNOWN
;
}
GRUB2/grub-2.04/grub-core/ventoy/ventoy.c
View file @
84c50066
...
...
@@ -37,6 +37,7 @@
#include <grub/efi/efi.h>
#endif
#include <grub/time.h>
#include <grub/relocator.h>
#include <grub/ventoy.h>
#include "ventoy_def.h"
...
...
@@ -100,6 +101,36 @@ int ventoy_is_efi_os(void)
return
g_efi_os
;
}
static
int
ventoy_get_fs_type
(
const
char
*
fs
)
{
if
(
NULL
==
fs
)
{
return
ventoy_fs_max
;
}
else
if
(
grub_strncmp
(
fs
,
"exfat"
,
5
)
==
0
)
{
return
ventoy_fs_exfat
;
}
else
if
(
grub_strncmp
(
fs
,
"ntfs"
,
4
)
==
0
)
{
return
ventoy_fs_ntfs
;
}
else
if
(
grub_strncmp
(
fs
,
"ext"
,
3
)
==
0
)
{
return
ventoy_fs_ext
;
}
else
if
(
grub_strncmp
(
fs
,
"xfs"
,
3
)
==
0
)
{
return
ventoy_fs_xfs
;
}
else
if
(
grub_strncmp
(
fs
,
"udf"
,
3
)
==
0
)
{
return
ventoy_fs_udf
;
}
return
ventoy_fs_max
;
}
static
int
ventoy_string_check
(
const
char
*
str
,
grub_char_check_func
check
)
{
if
(
!
str
)
...
...
@@ -942,6 +973,12 @@ static grub_err_t ventoy_cmd_list_img(grub_extcmd_context_t ctxt, int argc, char
goto
fail
;
}
if
(
ventoy_get_fs_type
(
fs
->
name
)
>=
ventoy_fs_max
)
{
debug
(
"unsupported fs:<%s>
\n
"
,
fs
->
name
);
goto
fail
;
}
grub_memset
(
&
g_img_iterator_head
,
0
,
sizeof
(
g_img_iterator_head
));
g_img_iterator_head
.
dirlen
=
1
;
...
...
@@ -1212,19 +1249,7 @@ void ventoy_fill_os_param(grub_file_t file, ventoy_os_param *param)
param
->
vtoy_disk_size
=
disk
->
total_sectors
*
(
1
<<
disk
->
log_sector_size
);
param
->
vtoy_disk_part_id
=
disk
->
partition
->
number
+
1
;
if
(
grub_strcmp
(
file
->
fs
->
name
,
"exfat"
)
==
0
)
{
param
->
vtoy_disk_part_type
=
0
;
}
else
if
(
grub_strcmp
(
file
->
fs
->
name
,
"ntfs"
)
==
0
)
{
param
->
vtoy_disk_part_type
=
1
;
}
else
{
param
->
vtoy_disk_part_type
=
0xFFFF
;
}
param
->
vtoy_disk_part_type
=
ventoy_get_fs_type
(
file
->
fs
->
name
);
pos
=
grub_strstr
(
file
->
name
,
"/"
);
if
(
!
pos
)
...
...
@@ -1251,6 +1276,52 @@ void ventoy_fill_os_param(grub_file_t file, ventoy_os_param *param)
return
;
}
static
int
ventoy_get_block_list
(
grub_file_t
file
,
ventoy_img_chunk_list
*
chunklist
,
grub_disk_addr_t
start
)
{
int
fs_type
;
grub_uint32_t
i
=
0
;
grub_uint32_t
sector
=
0
;
grub_uint32_t
count
=
0
;
grub_off_t
size
=
0
;
grub_off_t
read
=
0
;
fs_type
=
ventoy_get_fs_type
(
file
->
fs
->
name
);
if
(
fs_type
==
ventoy_fs_exfat
)
{
grub_fat_get_file_chunk
(
start
,
file
,
chunklist
);
}
else
{
file
->
read_hook
=
(
grub_disk_read_hook_t
)
grub_disk_blocklist_read
;
file
->
read_hook_data
=
chunklist
;
for
(
size
=
file
->
size
;
size
>
0
;
size
-=
read
)
{
read
=
(
size
>
VTOY_SIZE_1GB
)
?
VTOY_SIZE_1GB
:
size
;
grub_file_read
(
file
,
NULL
,
read
);
}
for
(
i
=
0
;
start
>
0
&&
i
<
chunklist
->
cur_chunk
;
i
++
)
{
chunklist
->
chunk
[
i
].
disk_start_sector
+=
start
;
chunklist
->
chunk
[
i
].
disk_end_sector
+=
start
;
}
if
(
ventoy_fs_udf
==
fs_type
)
{
for
(
i
=
0
;
i
<
chunklist
->
cur_chunk
;
i
++
)
{
count
=
(
chunklist
->
chunk
[
i
].
disk_end_sector
+
1
-
chunklist
->
chunk
[
i
].
disk_start_sector
)
>>
2
;
chunklist
->
chunk
[
i
].
img_start_sector
=
sector
;
chunklist
->
chunk
[
i
].
img_end_sector
=
sector
+
count
-
1
;
sector
+=
count
;
}
}
}
return
0
;
}
static
grub_err_t
ventoy_cmd_img_sector
(
grub_extcmd_context_t
ctxt
,
int
argc
,
char
**
args
)
{
grub_file_t
file
;
...
...
@@ -1280,8 +1351,7 @@ static grub_err_t ventoy_cmd_img_sector(grub_extcmd_context_t ctxt, int argc, ch
g_img_chunk_list
.
max_chunk
=
DEFAULT_CHUNK_NUM
;
g_img_chunk_list
.
cur_chunk
=
0
;
debug
(
"get fat file chunk part start:%llu
\n
"
,
(
unsigned
long
long
)
file
->
device
->
disk
->
partition
->
start
);
grub_fat_get_file_chunk
(
file
->
device
->
disk
->
partition
->
start
,
file
,
&
g_img_chunk_list
);
ventoy_get_block_list
(
file
,
&
g_img_chunk_list
,
file
->
device
->
disk
->
partition
->
start
);
grub_file_close
(
file
);
...
...
@@ -1311,6 +1381,121 @@ static grub_err_t ventoy_cmd_dump_img_sector(grub_extcmd_context_t ctxt, int arg
VENTOY_CMD_RETURN
(
GRUB_ERR_NONE
);
}
#ifdef GRUB_MACHINE_EFI
static
grub_err_t
ventoy_cmd_relocator_chaindata
(
grub_extcmd_context_t
ctxt
,
int
argc
,
char
**
args
)
{
(
void
)
ctxt
;
(
void
)
argc
;
(
void
)
args
;
return
0
;
}
#else
static
grub_err_t
ventoy_cmd_relocator_chaindata
(
grub_extcmd_context_t
ctxt
,
int
argc
,
char
**
args
)
{
int
rc
=
0
;
ulong
chain_len
=
0
;
char
*
chain_data
=
NULL
;
char
*
relocator_addr
=
NULL
;
grub_relocator_chunk_t
ch
;
struct
grub_relocator
*
relocator
=
NULL
;
char
envbuf
[
64
]
=
{
0
};
(
void
)
ctxt
;
(
void
)
argc
;
(
void
)
args
;
if
(
argc
!=
2
)
{
return
1
;
}
chain_data
=
(
char
*
)
grub_strtoul
(
args
[
0
],
NULL
,
16
);
chain_len
=
grub_strtoul
(
args
[
1
],
NULL
,
10
);
relocator
=
grub_relocator_new
();
if
(
!
relocator
)
{
debug
(
"grub_relocator_new failed %p %lu
\n
"
,
chain_data
,
chain_len
);
return
1
;
}
rc
=
grub_relocator_alloc_chunk_addr
(
relocator
,
&
ch
,
0x100000
,
// GRUB_LINUX_BZIMAGE_ADDR,
chain_len
);
if
(
rc
)
{
debug
(
"grub_relocator_alloc_chunk_addr failed %d %p %lu
\n
"
,
rc
,
chain_data
,
chain_len
);
grub_relocator_unload
(
relocator
);
return
1
;
}
relocator_addr
=
get_virtual_current_address
(
ch
);
grub_memcpy
(
relocator_addr
,
chain_data
,
chain_len
);
grub_relocator_unload
(
relocator
);
grub_snprintf
(
envbuf
,
sizeof
(
envbuf
),
"0x%lx"
,
(
unsigned
long
)
relocator_addr
);
grub_env_set
(
"vtoy_chain_relocator_addr"
,
envbuf
);
VENTOY_CMD_RETURN
(
GRUB_ERR_NONE
);
}
#endif
static
grub_err_t
ventoy_cmd_test_block_list
(
grub_extcmd_context_t
ctxt
,
int
argc
,
char
**
args
)
{
grub_uint32_t
i
;
grub_file_t
file
;
ventoy_img_chunk_list
chunklist
;
(
void
)
ctxt
;
(
void
)
argc
;
file
=
ventoy_grub_file_open
(
VENTOY_FILE_TYPE
,
"%s"
,
args
[
0
]);
if
(
!
file
)
{
return
grub_error
(
GRUB_ERR_BAD_ARGUMENT
,
"Can't open file %s
\n
"
,
args
[
0
]);
}
/* get image chunk data */
grub_memset
(
&
chunklist
,
0
,
sizeof
(
chunklist
));
chunklist
.
chunk
=
grub_malloc
(
sizeof
(
ventoy_img_chunk
)
*
DEFAULT_CHUNK_NUM
);
if
(
NULL
==
chunklist
.
chunk
)
{
return
grub_error
(
GRUB_ERR_OUT_OF_MEMORY
,
"Can't allocate image chunk memoty
\n
"
);
}
chunklist
.
max_chunk
=
DEFAULT_CHUNK_NUM
;
chunklist
.
cur_chunk
=
0
;
ventoy_get_block_list
(
file
,
&
chunklist
,
0
);
grub_file_close
(
file
);
grub_printf
(
"filesystem: <%s> entry number:<%u>
\n
"
,
file
->
fs
->
name
,
chunklist
.
cur_chunk
);
for
(
i
=
0
;
i
<
chunklist
.
cur_chunk
;
i
++
)
{
grub_printf
(
"%llu+%llu,"
,
(
ulonglong
)
chunklist
.
chunk
[
i
].
disk_start_sector
,
(
ulonglong
)(
chunklist
.
chunk
[
i
].
disk_end_sector
+
1
-
chunklist
.
chunk
[
i
].
disk_start_sector
));
}
grub_printf
(
"
\n
==================================
\n
"
);
for
(
i
=
0
;
i
<
chunklist
.
cur_chunk
;
i
++
)
{
grub_printf
(
"%2u: [%llu %llu] - [%llu %llu]
\n
"
,
i
,
(
ulonglong
)
chunklist
.
chunk
[
i
].
img_start_sector
,
(
ulonglong
)
chunklist
.
chunk
[
i
].
img_end_sector
,
(
ulonglong
)
chunklist
.
chunk
[
i
].
disk_start_sector
,
(
ulonglong
)
chunklist
.
chunk
[
i
].
disk_end_sector
);
}
grub_free
(
chunklist
.
chunk
);
VENTOY_CMD_RETURN
(
GRUB_ERR_NONE
);
}
static
grub_err_t
ventoy_cmd_add_replace_file
(
grub_extcmd_context_t
ctxt
,
int
argc
,
char
**
args
)
{
int
i
;
...
...
@@ -1412,7 +1597,7 @@ static grub_err_t ventoy_cmd_dynamic_menu(grub_extcmd_context_t ctxt, int argc,
if
(
argc
!=
2
)
{
debug
(
"Inv
l
aid argc %d
\n
"
,
argc
);
debug
(
"Inva
l
id argc %d
\n
"
,
argc
);
return
0
;
}
...
...
@@ -1635,6 +1820,8 @@ static cmd_para ventoy_cmds[] =
{
"vt_windows_chain_data"
,
ventoy_cmd_windows_chain_data
,
0
,
NULL
,
""
,
""
,
NULL
},
{
"vt_add_replace_file"
,
ventoy_cmd_add_replace_file
,
0
,
NULL
,
""
,
""
,
NULL
},
{
"vt_relocator_chaindata"
,
ventoy_cmd_relocator_chaindata
,
0
,
NULL
,
""
,
""
,
NULL
},
{
"vt_test_block_list"
,
ventoy_cmd_test_block_list
,
0
,
NULL
,
""
,
""
,
NULL
},
{
"vt_load_plugin"
,
ventoy_cmd_load_plugin
,
0
,
NULL
,
""
,
""
,
NULL
},
...
...
GRUB2/grub-2.04/grub-core/ventoy/ventoy_def.h
View file @
84c50066
...
...
@@ -23,6 +23,8 @@
#define VTOY_MAX_SCRIPT_BUF (4 * 1024 * 1024)
#define VTOY_SIZE_1GB 1073741824
#define JSON_SUCCESS 0
#define JSON_FAILED 1
#define JSON_NOT_FOUND 2
...
...
GRUB2/grub-2.04/grub-core/ventoy/ventoy_windows.c
View file @
84c50066
...
...
@@ -401,7 +401,7 @@ static int ventoy_update_all_hash(void *meta_data, wim_directory_entry *dir)
return
0
;
}
if
(
dir
->
len
==
0
)
if
(
dir
->
len
<
sizeof
(
wim_directory_entry
)
)
{
return
0
;
}
...
...
@@ -420,7 +420,7 @@ static int ventoy_update_all_hash(void *meta_data, wim_directory_entry *dir)
}
dir
=
(
wim_directory_entry
*
)((
char
*
)
dir
+
dir
->
len
);
}
while
(
dir
->
len
);
}
while
(
dir
->
len
>=
sizeof
(
wim_directory_entry
)
);
return
0
;
}
...
...
@@ -957,4 +957,3 @@ grub_err_t ventoy_cmd_windows_chain_data(grub_extcmd_context_t ctxt, int argc, c
VENTOY_CMD_RETURN
(
GRUB_ERR_NONE
);
}
GRUB2/grub-2.04/include/grub/disk.h
0 → 100644
View file @
84c50066
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GRUB_DISK_HEADER
#define GRUB_DISK_HEADER 1
#include <config.h>
#include <grub/symbol.h>
#include <grub/err.h>
#include <grub/types.h>
#include <grub/device.h>
/* For NULL. */
#include <grub/mm.h>
/* These are used to set a device id. When you add a new disk device,
you must define a new id for it here. */
enum
grub_disk_dev_id
{
GRUB_DISK_DEVICE_BIOSDISK_ID
,
GRUB_DISK_DEVICE_OFDISK_ID
,
GRUB_DISK_DEVICE_LOOPBACK_ID
,
GRUB_DISK_DEVICE_EFIDISK_ID
,
GRUB_DISK_DEVICE_DISKFILTER_ID
,
GRUB_DISK_DEVICE_HOST_ID
,
GRUB_DISK_DEVICE_ATA_ID
,
GRUB_DISK_DEVICE_MEMDISK_ID
,
GRUB_DISK_DEVICE_NAND_ID
,
GRUB_DISK_DEVICE_SCSI_ID
,
GRUB_DISK_DEVICE_CRYPTODISK_ID
,
GRUB_DISK_DEVICE_ARCDISK_ID
,
GRUB_DISK_DEVICE_HOSTDISK_ID
,
GRUB_DISK_DEVICE_PROCFS_ID
,
GRUB_DISK_DEVICE_CBFSDISK_ID
,
GRUB_DISK_DEVICE_UBOOTDISK_ID
,
GRUB_DISK_DEVICE_XEN
,
GRUB_DISK_DEVICE_OBDISK_ID
,
};
struct
grub_disk
;
#ifdef GRUB_UTIL
struct
grub_disk_memberlist
;
#endif
typedef
enum
{
GRUB_DISK_PULL_NONE
,
GRUB_DISK_PULL_REMOVABLE
,
GRUB_DISK_PULL_RESCAN
,
GRUB_DISK_PULL_MAX
}
grub_disk_pull_t
;
typedef
int
(
*
grub_disk_dev_iterate_hook_t
)
(
const
char
*
name
,
void
*
data
);
/* Disk device. */
struct
grub_disk_dev
{
/* The device name. */
const
char
*
name
;
/* The device id used by the cache manager. */
enum
grub_disk_dev_id
id
;
/* Call HOOK with each device name, until HOOK returns non-zero. */
int
(
*
disk_iterate
)
(
grub_disk_dev_iterate_hook_t
hook
,
void
*
hook_data
,
grub_disk_pull_t
pull
);
/* Open the device named NAME, and set up DISK. */
grub_err_t
(
*
disk_open
)
(
const
char
*
name
,
struct
grub_disk
*
disk
);
/* Close the disk DISK. */
void
(
*
disk_close
)
(
struct
grub_disk
*
disk
);
/* Read SIZE sectors from the sector SECTOR of the disk DISK into BUF. */
grub_err_t
(
*
disk_read
)
(
struct
grub_disk
*
disk
,
grub_disk_addr_t
sector
,
grub_size_t
size
,
char
*
buf
);
/* Write SIZE sectors from BUF into the sector SECTOR of the disk DISK. */
grub_err_t
(
*
disk_write
)
(
struct
grub_disk
*
disk
,
grub_disk_addr_t
sector
,
grub_size_t
size
,
const
char
*
buf
);
#ifdef GRUB_UTIL
struct
grub_disk_memberlist
*
(
*
disk_memberlist
)
(
struct
grub_disk
*
disk
);
const
char
*
(
*
disk_raidname
)
(
struct
grub_disk
*
disk
);
#endif
/* The next disk device. */
struct
grub_disk_dev
*
next
;
};
typedef
struct
grub_disk_dev
*
grub_disk_dev_t
;
extern
grub_disk_dev_t
EXPORT_VAR
(
grub_disk_dev_list
);
struct
grub_partition
;
typedef
void
(
*
grub_disk_read_hook_t
)
(
grub_disk_addr_t
sector
,
unsigned
offset
,
unsigned
length
,
void
*
data
);
/* Disk. */
struct
grub_disk
{
/* The disk name. */
const
char
*
name
;
/* The underlying disk device. */
grub_disk_dev_t
dev
;
/* The total number of sectors. */
grub_uint64_t
total_sectors
;
/* Logarithm of sector size. */
unsigned
int
log_sector_size
;
/* Maximum number of sectors read divided by GRUB_DISK_CACHE_SIZE. */
unsigned
int
max_agglomerate
;
/* The id used by the disk cache manager. */
unsigned
long
id
;
/* The partition information. This is machine-specific. */
struct
grub_partition
*
partition
;
/* Called when a sector was read. OFFSET is between 0 and
the sector size minus 1, and LENGTH is between 0 and the sector size. */
grub_disk_read_hook_t
read_hook
;
/* Caller-specific data passed to the read hook. */
void
*
read_hook_data
;
/* Device-specific data. */
void
*
data
;
};
typedef
struct
grub_disk
*
grub_disk_t
;
#ifdef GRUB_UTIL
struct
grub_disk_memberlist
{
grub_disk_t
disk
;
struct
grub_disk_memberlist
*
next
;
};
typedef
struct
grub_disk_memberlist
*
grub_disk_memberlist_t
;
#endif
/* The sector size. */
#define GRUB_DISK_SECTOR_SIZE 0x200
#define GRUB_DISK_SECTOR_BITS 9
/* The maximum number of disk caches. */
#define GRUB_DISK_CACHE_NUM 1021
/* The size of a disk cache in 512B units. Must be at least as big as the
largest supported sector size, currently 16K. */
#define GRUB_DISK_CACHE_BITS 6
#define GRUB_DISK_CACHE_SIZE (1 << GRUB_DISK_CACHE_BITS)
#define GRUB_DISK_MAX_MAX_AGGLOMERATE ((1 << (30 - GRUB_DISK_CACHE_BITS - GRUB_DISK_SECTOR_BITS)) - 1)
/* Return value of grub_disk_get_size() in case disk size is unknown. */
#define GRUB_DISK_SIZE_UNKNOWN 0xffffffffffffffffULL
/* This is called from the memory manager. */
void
grub_disk_cache_invalidate_all
(
void
);
void
EXPORT_FUNC
(
grub_disk_dev_register
)
(
grub_disk_dev_t
dev
);
void
EXPORT_FUNC
(
grub_disk_dev_unregister
)
(
grub_disk_dev_t
dev
);
static
inline
int
grub_disk_dev_iterate
(
grub_disk_dev_iterate_hook_t
hook
,
void
*
hook_data
)
{
grub_disk_dev_t
p
;
grub_disk_pull_t
pull
;
for
(
pull
=
0
;
pull
<
GRUB_DISK_PULL_MAX
;
pull
++
)
for
(
p
=
grub_disk_dev_list
;
p
;
p
=
p
->
next
)
if
(
p
->
disk_iterate
&&
(
p
->
disk_iterate
)
(
hook
,
hook_data
,
pull
))
return
1
;
return
0
;
}
grub_disk_t
EXPORT_FUNC
(
grub_disk_open
)
(
const
char
*
name
);
void
EXPORT_FUNC
(
grub_disk_close
)
(
grub_disk_t
disk
);
grub_err_t
EXPORT_FUNC
(
grub_disk_blocklist_read
)(
void
*
chunklist
,
grub_uint64_t
sector
,
grub_uint64_t
size
,
grub_uint32_t
log_sector_size
);
grub_err_t
EXPORT_FUNC
(
grub_disk_read
)
(
grub_disk_t
disk
,
grub_disk_addr_t
sector
,
grub_off_t
offset
,
grub_size_t
size
,
void
*
buf
);
grub_err_t
grub_disk_write
(
grub_disk_t
disk
,
grub_disk_addr_t
sector
,
grub_off_t
offset
,
grub_size_t
size
,
const
void
*
buf
);
extern
grub_err_t
(
*
EXPORT_VAR
(
grub_disk_write_weak
))
(
grub_disk_t
disk
,
grub_disk_addr_t
sector
,
grub_off_t
offset
,
grub_size_t
size
,
const
void
*
buf
);
grub_uint64_t
EXPORT_FUNC
(
grub_disk_get_size
)
(
grub_disk_t
disk
);
#if DISK_CACHE_STATS
void
EXPORT_FUNC
(
grub_disk_cache_get_performance
)
(
unsigned
long
*
hits
,
unsigned
long
*
misses
);
#endif
extern
void
(
*
EXPORT_VAR
(
grub_disk_firmware_fini
))
(
void
);
extern
int
EXPORT_VAR
(
grub_disk_firmware_is_tainted
);
static
inline
void
grub_stop_disk_firmware
(
void
)
{
/* To prevent two drivers operating on the same disks. */
grub_disk_firmware_is_tainted
=
1
;
if
(
grub_disk_firmware_fini
)
{
grub_disk_firmware_fini
();
grub_disk_firmware_fini
=
NULL
;
}
}
/* Disk cache. */
struct
grub_disk_cache
{
enum
grub_disk_dev_id
dev_id
;
unsigned
long
disk_id
;
grub_disk_addr_t
sector
;
char
*
data
;
int
lock
;
};
extern
struct
grub_disk_cache
EXPORT_VAR
(
grub_disk_cache_table
)[
GRUB_DISK_CACHE_NUM
];
#if defined (GRUB_UTIL)
void
grub_lvm_init
(
void
);
void
grub_ldm_init
(
void
);
void
grub_mdraid09_init
(
void
);
void
grub_mdraid1x_init
(
void
);
void
grub_diskfilter_init
(
void
);
void
grub_lvm_fini
(
void
);
void
grub_ldm_fini
(
void
);
void
grub_mdraid09_fini
(
void
);
void
grub_mdraid1x_fini
(
void
);
void
grub_diskfilter_fini
(
void
);
#endif
#endif
/* ! GRUB_DISK_HEADER */
GRUB2/grub-2.04/include/grub/ventoy.h
View file @
84c50066
...
...
@@ -28,6 +28,17 @@
#define VENTOY_GUID { 0x77772020, 0x2e77, 0x6576, { 0x6e, 0x74, 0x6f, 0x79, 0x2e, 0x6e, 0x65, 0x74 }}
typedef
enum
ventoy_fs_type
{
ventoy_fs_exfat
=
0
,
/* 0: exfat */
ventoy_fs_ntfs
,
/* 1: NTFS */
ventoy_fs_ext
,
/* 2: ext2/ext3/ext4 */
ventoy_fs_xfs
,
/* 3: XFS */
ventoy_fs_udf
,
/* 4: UDF */
ventoy_fs_max
}
ventoy_fs_type
;
#pragma pack(1)
typedef
struct
ventoy_guid
...
...
INSTALL/EFI/BOOT/grubx64_real.efi
View file @
84c50066
No preview for this file type
INSTALL/Ventoy2Disk.exe
View file @
84c50066
No preview for this file type
INSTALL/Ventoy2Disk.sh
View file @
84c50066
...
...
@@ -9,12 +9,16 @@ fi
.
./tool/ventoy_lib.sh
print_usage
()
{
echo
'Usage: Ventoy
Installer.sh
OPTION /dev/sdX'
echo
'
OPTION
:'
echo
'Usage: Ventoy
2Disk.sh CMD [
OPTION
]
/dev/sdX'
echo
'
CMD
:'
echo
' -i install ventoy to sdX (fail if disk already installed with ventoy)'
echo
' -u update ventoy in sdX'
echo
' -I force install ventoy to sdX (no matter installed or not)'
echo
''
echo
' OPTION: (optional)'
echo
' -s enable secure boot support (default is disabled)'
echo
''
}
echo
''
...
...
@@ -38,6 +42,7 @@ while [ -n "$1" ]; do
SECUREBOOT
=
"YES"
else
if
!
[
-b
"
$1
"
]
;
then
vterr
"
$1
is NOT a valid device"
print_usage
cd
$OLDDIR
exit
1
...
...
@@ -54,13 +59,25 @@ if [ -z "$MODE" ]; then
exit
1
fi
if
[
-z
"
$SUDO_USER
"
]
;
then
if
[
"
$USER
"
!=
"root"
]
;
then
vterr
"EUID is
$EUID
root permission is required."
echo
''
cd
$OLDDIR
exit
1
fi
if
!
[
-b
"
$DISK
"
]
;
then
vterr
"Disk
$DISK
does not exist"
cd
$OLDDIR
exit
1
fi
if
[
-e
/sys/class/block/
${
DISK
#/dev/
}
/start
]
;
then
vterr
"
$DISK
is a partition, please use the whole disk"
cd
$OLDDIR
exit
1
fi
if
dd
if
=
"
$DISK
"
of
=
/dev/null
bs
=
1
count
=
1
>
/dev/null 2>&1
;
then
vtdebug
"root permission check ok ..."
else
vterr
"Failed to access
$DISK
, maybe root privilege is needed!"
echo
''
cd
$OLDDIR
exit
1
fi
vtdebug
"MODE=
$MODE
FORCE=
$FORCE
"
...
...
@@ -93,20 +110,6 @@ if ! check_tool_work_ok; then
exit
1
fi
if
!
[
-b
"
$DISK
"
]
;
then
vterr
"Disk
$DISK
does not exist"
cd
$OLDDIR
exit
1
fi
if
[
-e
/sys/class/block/
${
DISK
#/dev/
}
/start
]
;
then
vterr
"
$DISK
is a partition, please use the whole disk"
cd
$OLDDIR
exit
1
fi
grep
"^
$DISK
"
/proc/mounts |
while
read
mtline
;
do
mtpnt
=
$(
echo
$mtline
|
awk
'{print $DISK}'
)
vtdebug
"Trying to umount
$mtpnt
..."
...
...
@@ -242,6 +245,7 @@ if [ "$MODE" = "install" ]; then
rm
-f
./tmp_mnt/EFI/BOOT/BOOTX64.EFI
rm
-f
./tmp_mnt/EFI/BOOT/grubx64.efi
rm
-f
./tmp_mnt/EFI/BOOT/MokManager.efi
rm
-f
./tmp_mnt/ENROLL_THIS_KEY_IN_MOKMANAGER.cer
mv
./tmp_mnt/EFI/BOOT/grubx64_real.efi ./tmp_mnt/EFI/BOOT/BOOTX64.EFI
umount ./tmp_mnt
...
...
@@ -305,6 +309,7 @@ else
rm
-f
./tmp_mnt/EFI/BOOT/BOOTX64.EFI
rm
-f
./tmp_mnt/EFI/BOOT/grubx64.efi
rm
-f
./tmp_mnt/EFI/BOOT/MokManager.efi
rm
-f
./tmp_mnt/ENROLL_THIS_KEY_IN_MOKMANAGER.cer
mv
./tmp_mnt/EFI/BOOT/grubx64_real.efi ./tmp_mnt/EFI/BOOT/BOOTX64.EFI
umount ./tmp_mnt
...
...
INSTALL/grub/grub.cfg
View file @
84c50066
...
...
@@ -50,6 +50,21 @@ function get_os_type {
fi
}
function vt_check_pe {
unset VT_PE_SUPPORT
if [ -f $1/HBCD_PE.ini ]; then
set ventoy_compatible=YES
set VT_PE_SUPPORT=YES
elif [ -f $1/easyu.flg ]; then
set VT_PE_SUPPORT=YES
elif [ -f $1/USM.ICO ]; then
set VT_PE_SUPPORT=YES
elif [ -d $1/USM_TOOL ]; then
set VT_PE_SUPPORT=YES
fi
}
function locate_initrd {
vt_linux_locate_initrd
...
...
@@ -62,7 +77,8 @@ function locate_initrd {
function find_wim_file {
unset ventoy_wim_file
for file in "sources/boot.wim" "sources/BOOT.WIM" "Sources/Win10PEx64.WIM" "boot/BOOT.WIM" "winpe_x64.wim"; do
for file in "sources/boot.wim" "sources/BOOT.WIM" "Sources/Win10PEx64.WIM" "boot/BOOT.WIM" \
"winpe_x64.wim" "boot/10pex64.wim" "BOOT/USM1PE6L.WIM" "BOOT/USM1PE6F.WIM"; do
if [ -e $1/$file ]; then
set ventoy_wim_file=$1/$file
break
...
...
@@ -114,6 +130,8 @@ function distro_specify_initrd_file_phase2 {
vt_linux_specify_initrd_file /isolinux/initramfs
elif [ -f (loop)/boot/iniramfs.igz ]; then
vt_linux_specify_initrd_file /boot/iniramfs.igz
elif [ -f (loop)/initrd-x86_64 ]; then
vt_linux_specify_initrd_file /initrd-x86_64
fi
}
...
...
@@ -248,10 +266,11 @@ function uefi_iso_menu_func {
vt_img_sector ${1}${chosen_path}
if [ "$vtoy_os" = "Windows" ]; then
if [ "$ventoy_fs_probe" = "iso9660" ]; then
set ventoy_compatible=YES
elif [ -f (loop)/HBCD_PE.ini ]; then
set ventoy_compatible=YES
vt_check_pe (loop)
if [ "$VT_PE_SUPPORT" != "YES" ]; then
if [ "$ventoy_fs_probe" = "iso9660" ]; then
set ventoy_compatible=YES
fi
fi
uefi_windows_menu_func $1 ${chosen_path}
...
...
@@ -293,8 +312,7 @@ function legacy_windows_menu_func {
fi
if [ -n "$vtoy_chain_mem_addr" ]; then
linux16 $vtoy_path/ipxe.krn ${vtdebug_flag} ibft
initrd16 mem:${vtoy_chain_mem_addr}:size:${vtoy_chain_mem_size}
linux16 $vtoy_path/ipxe.krn ${vtdebug_flag} ibft mem:${vtoy_chain_mem_addr}:size:${vtoy_chain_mem_size}
boot
else
echo "chain empty failed"
...
...
@@ -349,9 +367,8 @@ function legacy_linux_menu_func {
sleep 5
fi
if [ -n "$vtoy_chain_mem_addr" ]; then
linux16 $vtoy_path/ipxe.krn ${vtdebug_flag}
initrd16 mem:${vtoy_chain_mem_addr}:size:${vtoy_chain_mem_size}
if [ -n "$vtoy_chain_mem_addr" ]; then
linux16 $vtoy_path/ipxe.krn ${vtdebug_flag} mem:${vtoy_chain_mem_addr}:size:${vtoy_chain_mem_size}
boot
else
echo "chain empty failed"
...
...
@@ -389,10 +406,11 @@ function legacy_iso_menu_func {
vt_img_sector ${1}${chosen_path}
if [ "$vtoy_os" = "Windows" ]; then
if [ "$ventoy_fs_probe" = "iso9660" ]; then
set ventoy_compatible=YES
elif [ -f (loop)/HBCD_PE.ini ]; then
set ventoy_compatible=YES
vt_check_pe (loop)
if [ "$VT_PE_SUPPORT" != "YES" ]; then
if [ "$ventoy_fs_probe" = "iso9660" ]; then
set ventoy_compatible=YES
fi
fi
legacy_windows_menu_func $1 ${chosen_path}
...
...
@@ -435,7 +453,7 @@ function common_menuentry {
#############################################################
#############################################################
set VENTOY_VERSION="1.0.
0
9"
set VENTOY_VERSION="1.0.9
Y
"
# Default menu display mode, you can change it as you want.
...
...
INSTALL/grub/i386-pc/core.img
View file @
84c50066
No preview for this file type
INSTALL/tool/ventoy_lib.sh
View file @
84c50066
...
...
@@ -14,16 +14,6 @@ ventoy_true() {
}
ventoy_is_linux64
()
{
if
[
-e
/lib64
]
;
then
ventoy_true
return
fi
if
[
-e
/usr/lib64
]
;
then
ventoy_true
return
fi
if
uname
-a
| egrep
-q
'x86_64|amd64'
;
then
ventoy_true
return
...
...
@@ -165,12 +155,12 @@ is_disk_contains_ventoy() {
return
fi
PART1_TYPE
=
$(
dd
if
=
$DISK
bs
=
1
count
=
1
skip
=
450
status
=
none | ./tool/hexdump
-n1
-e
'1/1 "%02X"'
)
if
[
"
$PART1_TYPE
"
!=
"07"
]
;
then
vtdebug
"part1 type is
$PART2_TYPE
not 07"
ventoy_false
return
fi
#
PART1_TYPE=$(dd if=$DISK bs=1 count=1 skip=450 status=none | ./tool/hexdump -n1 -e '1/1 "%02X"')
#
if [ "$PART1_TYPE" != "07" ]; then
#
vtdebug "part1 type is $PART2_TYPE not 07"
#
ventoy_false
#
return
#
fi
if
[
-e
/sys/class/block/
${
PART1
#/dev/
}
/start
]
;
then
PART1_START
=
$(
cat
/sys/class/block/
${
PART1
#/dev/
}
/start
)
...
...
INSTALL/ventoy/ipxe.krn
View file @
84c50066
No preview for this file type
INSTALL/ventoy/ventoy.cpio
View file @
84c50066
No preview for this file type
Prev
1
2
Next
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment