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
93996cf7
Commit
93996cf7
authored
May 13, 2021
by
longpanda
Browse files
1. Optimization for WIMBOOT mode.
2. Add WIMBOOT for UEFI mode.
parent
ca62128f
Changes
120
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
4100 additions
and
0 deletions
+4100
-0
wimboot/wimboot-2.7.3/src/stdio.h
wimboot/wimboot-2.7.3/src/stdio.h
+46
-0
wimboot/wimboot-2.7.3/src/stdlib.h
wimboot/wimboot-2.7.3/src/stdlib.h
+32
-0
wimboot/wimboot-2.7.3/src/string.c
wimboot/wimboot-2.7.3/src/string.c
+352
-0
wimboot/wimboot-2.7.3/src/string.h
wimboot/wimboot-2.7.3/src/string.h
+39
-0
wimboot/wimboot-2.7.3/src/strings.h
wimboot/wimboot-2.7.3/src/strings.h
+32
-0
wimboot/wimboot-2.7.3/src/vdisk.c
wimboot/wimboot-2.7.3/src/vdisk.c
+665
-0
wimboot/wimboot-2.7.3/src/vdisk.h
wimboot/wimboot-2.7.3/src/vdisk.h
+623
-0
wimboot/wimboot-2.7.3/src/vsprintf.c
wimboot/wimboot-2.7.3/src/vsprintf.c
+12
-0
wimboot/wimboot-2.7.3/src/wchar.h
wimboot/wimboot-2.7.3/src/wchar.h
+56
-0
wimboot/wimboot-2.7.3/src/wctype.h
wimboot/wimboot-2.7.3/src/wctype.h
+53
-0
wimboot/wimboot-2.7.3/src/wim.c
wimboot/wimboot-2.7.3/src/wim.c
+544
-0
wimboot/wimboot-2.7.3/src/wim.h
wimboot/wimboot-2.7.3/src/wim.h
+196
-0
wimboot/wimboot-2.7.3/src/wimboot.h
wimboot/wimboot-2.7.3/src/wimboot.h
+159
-0
wimboot/wimboot-2.7.3/src/wimfile.c
wimboot/wimboot-2.7.3/src/wimfile.c
+151
-0
wimboot/wimboot-2.7.3/src/wimfile.h
wimboot/wimboot-2.7.3/src/wimfile.h
+41
-0
wimboot/wimboot-2.7.3/src/wimpatch.c
wimboot/wimboot-2.7.3/src/wimpatch.c
+811
-0
wimboot/wimboot-2.7.3/src/wimpatch.h
wimboot/wimboot-2.7.3/src/wimpatch.h
+37
-0
wimboot/wimboot-2.7.3/src/x86_64.i
wimboot/wimboot-2.7.3/src/x86_64.i
+1
-0
wimboot/wimboot-2.7.3/src/xca.c
wimboot/wimboot-2.7.3/src/xca.c
+162
-0
wimboot/wimboot-2.7.3/src/xca.h
wimboot/wimboot-2.7.3/src/xca.h
+88
-0
No files found.
wimboot/wimboot-2.7.3/src/stdio.h
0 → 100644
View file @
93996cf7
#ifndef _STDIO_H
#define _STDIO_H
/*
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
* @file
*
* Standard Input/Output
*
*/
#include <stdint.h>
#include <stdarg.h>
extern
int
putchar
(
int
character
);
extern
int
getchar
(
void
);
extern
int
__attribute__
((
format
(
printf
,
1
,
2
)
))
printf
(
const
char
*
fmt
,
...
);
extern
int
__attribute__
((
format
(
printf
,
3
,
4
)
))
snprintf
(
char
*
buf
,
size_t
size
,
const
char
*
fmt
,
...
);
extern
int
vprintf
(
const
char
*
fmt
,
va_list
args
);
extern
int
vsnprintf
(
char
*
buf
,
size_t
size
,
const
char
*
fmt
,
va_list
args
);
#endif
/* _STDIO_H */
wimboot/wimboot-2.7.3/src/stdlib.h
0 → 100644
View file @
93996cf7
#ifndef _STDLIB_H
#define _STDLIB_H
/*
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
* @file
*
* Standard library
*
*/
extern
unsigned
long
strtoul
(
const
char
*
nptr
,
char
**
endptr
,
int
base
);
#endif
/* _STDLIB_H */
wimboot/wimboot-2.7.3/src/string.c
0 → 100644
View file @
93996cf7
/*
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
* @file
*
* String functions
*
*/
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include "ctype.h"
#include "wctype.h"
/**
* Copy memory area
*
* @v dest Destination address
* @v src Source address
* @v len Length
* @ret dest Destination address
*/
void
*
memcpy
(
void
*
dest
,
const
void
*
src
,
size_t
len
)
{
void
*
edi
=
dest
;
const
void
*
esi
=
src
;
int
discard_ecx
;
/* Perform dword-based copy for bulk, then byte-based for remainder */
__asm__
__volatile__
(
"rep movsl"
:
"=&D"
(
edi
),
"=&S"
(
esi
),
"=&c"
(
discard_ecx
)
:
"0"
(
edi
),
"1"
(
esi
),
"2"
(
len
>>
2
)
:
"memory"
);
__asm__
__volatile__
(
"rep movsb"
:
"=&D"
(
edi
),
"=&S"
(
esi
),
"=&c"
(
discard_ecx
)
:
"0"
(
edi
),
"1"
(
esi
),
"2"
(
len
&
3
)
:
"memory"
);
return
dest
;
}
/**
* Copy memory area backwards
*
* @v dest Destination address
* @v src Source address
* @v len Length
* @ret dest Destination address
*/
static
void
*
memcpy_reverse
(
void
*
dest
,
const
void
*
src
,
size_t
len
)
{
void
*
edi
=
(
dest
+
len
-
1
);
const
void
*
esi
=
(
src
+
len
-
1
);
int
discard_ecx
;
/* Assume memmove() is not performance-critical, and perform a
* bytewise copy for simplicity.
*
* Disable interrupts to avoid known problems on platforms
* that assume the direction flag always remains cleared.
*/
__asm__
__volatile__
(
"pushf
\n\t
"
"cli
\n\t
"
"std
\n\t
"
"rep movsb
\n\t
"
"popf
\n\t
"
:
"=&D"
(
edi
),
"=&S"
(
esi
),
"=&c"
(
discard_ecx
)
:
"0"
(
edi
),
"1"
(
esi
),
"2"
(
len
)
:
"memory"
);
return
dest
;
}
/**
* Copy (possibly overlapping) memory area
*
* @v dest Destination address
* @v src Source address
* @v len Length
* @ret dest Destination address
*/
void
*
memmove
(
void
*
dest
,
const
void
*
src
,
size_t
len
)
{
if
(
dest
<=
src
)
{
return
memcpy
(
dest
,
src
,
len
);
}
else
{
return
memcpy_reverse
(
dest
,
src
,
len
);
}
}
/**
* Set memory area
*
* @v dest Destination address
* @v src Source address
* @v len Length
* @ret dest Destination address
*/
void
*
memset
(
void
*
dest
,
int
c
,
size_t
len
)
{
void
*
edi
=
dest
;
int
eax
=
c
;
int
discard_ecx
;
/* Expand byte to whole dword */
eax
|=
(
eax
<<
8
);
eax
|=
(
eax
<<
16
);
/* Perform dword-based set for bulk, then byte-based for remainder */
__asm__
__volatile__
(
"rep stosl"
:
"=&D"
(
edi
),
"=&a"
(
eax
),
"=&c"
(
discard_ecx
)
:
"0"
(
edi
),
"1"
(
eax
),
"2"
(
len
>>
2
)
:
"memory"
);
__asm__
__volatile__
(
"rep stosb"
:
"=&D"
(
edi
),
"=&a"
(
eax
),
"=&c"
(
discard_ecx
)
:
"0"
(
edi
),
"1"
(
eax
),
"2"
(
len
&
3
)
:
"memory"
);
return
dest
;
}
/**
* Compare memory areas
*
* @v src1 First source area
* @v src2 Second source area
* @v len Length
* @ret diff Difference
*/
int
memcmp
(
const
void
*
src1
,
const
void
*
src2
,
size_t
len
)
{
const
uint8_t
*
bytes1
=
src1
;
const
uint8_t
*
bytes2
=
src2
;
int
diff
;
while
(
len
--
)
{
if
(
(
diff
=
(
*
(
bytes1
++
)
-
*
(
bytes2
++
)
)
)
)
return
diff
;
}
return
0
;
}
/**
* Compare two strings
*
* @v str1 First string
* @v str2 Second string
* @ret diff Difference
*/
int
strcmp
(
const
char
*
str1
,
const
char
*
str2
)
{
int
c1
;
int
c2
;
do
{
c1
=
*
(
str1
++
);
c2
=
*
(
str2
++
);
}
while
(
(
c1
!=
'\0'
)
&&
(
c1
==
c2
)
);
return
(
c1
-
c2
);
}
/**
* Compare two strings, case-insensitively
*
* @v str1 First string
* @v str2 Second string
* @ret diff Difference
*/
int
strcasecmp
(
const
char
*
str1
,
const
char
*
str2
)
{
int
c1
;
int
c2
;
do
{
c1
=
toupper
(
*
(
str1
++
)
);
c2
=
toupper
(
*
(
str2
++
)
);
}
while
(
(
c1
!=
'\0'
)
&&
(
c1
==
c2
)
);
return
(
c1
-
c2
);
}
/**
* Compare two wide-character strings, case-insensitively
*
* @v str1 First string
* @v str2 Second string
* @ret diff Difference
*/
int
wcscasecmp
(
const
wchar_t
*
str1
,
const
wchar_t
*
str2
)
{
int
c1
;
int
c2
;
do
{
c1
=
towupper
(
*
(
str1
++
)
);
c2
=
towupper
(
*
(
str2
++
)
);
}
while
(
(
c1
!=
L'\0'
)
&&
(
c1
==
c2
)
);
return
(
c1
-
c2
);
}
/**
* Get length of string
*
* @v str String
* @ret len Length
*/
size_t
strlen
(
const
char
*
str
)
{
size_t
len
=
0
;
while
(
*
(
str
++
)
)
len
++
;
return
len
;
}
/**
* Get length of wide-character string
*
* @v str String
* @ret len Length (in characters)
*/
size_t
wcslen
(
const
wchar_t
*
str
)
{
size_t
len
=
0
;
while
(
*
(
str
++
)
)
len
++
;
return
len
;
}
/**
* Find character in wide-character string
*
* @v str String
* @v c Wide character
* @ret first First occurrence of wide character in string, or NULL
*/
wchar_t
*
wcschr
(
const
wchar_t
*
str
,
wchar_t
c
)
{
for
(
;
*
str
;
str
++
)
{
if
(
*
str
==
c
)
return
(
(
wchar_t
*
)
str
);
}
return
NULL
;
}
char
*
strchr
(
const
char
*
str
,
char
c
)
{
for
(
;
*
str
;
str
++
)
{
if
(
*
str
==
c
)
return
(
(
char
*
)
str
);
}
return
NULL
;
}
/**
* Check to see if character is a space
*
* @v c Character
* @ret isspace Character is a space
*/
int
isspace
(
int
c
)
{
switch
(
c
)
{
case
' '
:
case
'\f'
:
case
'\n'
:
case
'\r'
:
case
'\t'
:
case
'\v'
:
return
1
;
default:
return
0
;
}
}
/**
* Convert a string to an unsigned integer
*
* @v nptr String
* @v endptr End pointer to fill in (or NULL)
* @v base Numeric base
* @ret val Value
*/
unsigned
long
strtoul
(
const
char
*
nptr
,
char
**
endptr
,
int
base
)
{
unsigned
long
val
=
0
;
int
negate
=
0
;
unsigned
int
digit
;
/* Skip any leading whitespace */
while
(
isspace
(
*
nptr
)
)
nptr
++
;
/* Parse sign, if present */
if
(
*
nptr
==
'+'
)
{
nptr
++
;
}
else
if
(
*
nptr
==
'-'
)
{
nptr
++
;
negate
=
1
;
}
/* Parse base */
if
(
base
==
0
)
{
/* Default to decimal */
base
=
10
;
/* Check for octal or hexadecimal markers */
if
(
*
nptr
==
'0'
)
{
nptr
++
;
base
=
8
;
if
(
(
*
nptr
|
0x20
)
==
'x'
)
{
nptr
++
;
base
=
16
;
}
}
}
/* Parse digits */
for
(
;
;
nptr
++
)
{
digit
=
*
nptr
;
if
(
digit
>=
'a'
)
{
digit
=
(
digit
-
'a'
+
10
);
}
else
if
(
digit
>=
'A'
)
{
digit
=
(
digit
-
'A'
+
10
);
}
else
if
(
digit
<=
'9'
)
{
digit
=
(
digit
-
'0'
);
}
if
(
digit
>=
(
unsigned
int
)
base
)
break
;
val
=
(
(
val
*
base
)
+
digit
);
}
/* Record end marker, if applicable */
if
(
endptr
)
*
endptr
=
(
(
char
*
)
nptr
);
/* Return value */
return
(
negate
?
-
val
:
val
);
}
wimboot/wimboot-2.7.3/src/string.h
0 → 100644
View file @
93996cf7
#ifndef _STRING_H
#define _STRING_H
/*
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
* @file
*
* String operations
*
*/
#include <stdint.h>
extern
void
*
memcpy
(
void
*
dest
,
const
void
*
src
,
size_t
len
);
extern
void
*
memmove
(
void
*
dest
,
const
void
*
src
,
size_t
len
);
extern
void
*
memset
(
void
*
dest
,
int
c
,
size_t
len
);
extern
int
memcmp
(
const
void
*
src1
,
const
void
*
src2
,
size_t
len
);
extern
int
strcmp
(
const
char
*
str1
,
const
char
*
str2
);
extern
size_t
strlen
(
const
char
*
str
);
#endif
/* _STRING_H */
wimboot/wimboot-2.7.3/src/strings.h
0 → 100644
View file @
93996cf7
#ifndef _STRINGS_H
#define _STRINGS_H
/*
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
* @file
*
* String operations
*
*/
extern
int
strcasecmp
(
const
char
*
str1
,
const
char
*
str2
);
#endif
/* _STRINGS_H */
wimboot/wimboot-2.7.3/src/vdisk.c
0 → 100644
View file @
93996cf7
/*
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
* @file
*
* Virtual disk
*
*/
#include <stddef.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include "ctype.h"
#include "wimboot.h"
#include "vdisk.h"
/** Virtual files */
struct
vdisk_file
vdisk_files
[
VDISK_MAX_FILES
];
/**
* Read from virtual Master Boot Record
*
* @v lba Starting LBA
* @v count Number of blocks to read
* @v data Data buffer
*/
static
void
vdisk_mbr
(
uint64_t
lba
__unused
,
unsigned
int
count
__unused
,
void
*
data
)
{
struct
vdisk_mbr
*
mbr
=
data
;
/* Construct MBR */
memset
(
mbr
,
0
,
sizeof
(
*
mbr
)
);
mbr
->
partitions
[
0
].
bootable
=
VDISK_MBR_BOOTABLE
;
mbr
->
partitions
[
0
].
type
=
VDISK_MBR_TYPE_FAT32
;
mbr
->
partitions
[
0
].
start
=
VDISK_PARTITION_LBA
;
mbr
->
partitions
[
0
].
length
=
VDISK_PARTITION_COUNT
;
mbr
->
signature
=
VDISK_MBR_SIGNATURE
;
mbr
->
magic
=
VDISK_MBR_MAGIC
;
}
/**
* Read from virtual Volume Boot Record
*
* @v lba Starting LBA
* @v count Number of blocks to read
* @v data Data buffer
*/
static
void
vdisk_vbr
(
uint64_t
lba
__unused
,
unsigned
int
count
__unused
,
void
*
data
)
{
struct
vdisk_vbr
*
vbr
=
data
;
/* Construct VBR */
memset
(
vbr
,
0
,
sizeof
(
*
vbr
)
);
vbr
->
jump
[
0
]
=
VDISK_VBR_JUMP_WTF_MS
;
memcpy
(
vbr
->
oemid
,
VDISK_VBR_OEMID
,
sizeof
(
vbr
->
oemid
)
);
vbr
->
bytes_per_sector
=
VDISK_SECTOR_SIZE
;
vbr
->
sectors_per_cluster
=
VDISK_CLUSTER_COUNT
;
vbr
->
reserved_sectors
=
VDISK_RESERVED_COUNT
;
vbr
->
fats
=
1
;
vbr
->
media
=
VDISK_VBR_MEDIA
;
vbr
->
sectors_per_track
=
VDISK_SECTORS_PER_TRACK
;
vbr
->
heads
=
VDISK_HEADS
;
vbr
->
hidden_sectors
=
VDISK_VBR_LBA
;
vbr
->
sectors
=
VDISK_PARTITION_COUNT
;
vbr
->
sectors_per_fat
=
VDISK_SECTORS_PER_FAT
;
vbr
->
root
=
VDISK_ROOT_CLUSTER
;
vbr
->
fsinfo
=
VDISK_FSINFO_SECTOR
;
vbr
->
backup
=
VDISK_BACKUP_VBR_SECTOR
;
vbr
->
signature
=
VDISK_VBR_SIGNATURE
;
vbr
->
serial
=
VDISK_VBR_SERIAL
;
memcpy
(
vbr
->
label
,
VDISK_VBR_LABEL
,
sizeof
(
vbr
->
label
)
);
memcpy
(
vbr
->
system
,
VDISK_VBR_SYSTEM
,
sizeof
(
vbr
->
system
)
);
vbr
->
magic
=
VDISK_VBR_MAGIC
;
}
/**
* Read from virtual FSInfo
*
* @v lba Starting LBA
* @v count Number of blocks to read
* @v data Data buffer
*/
static
void
vdisk_fsinfo
(
uint64_t
lba
__unused
,
unsigned
int
count
__unused
,
void
*
data
)
{
struct
vdisk_fsinfo
*
fsinfo
=
data
;
/* Construct FSInfo */
memset
(
fsinfo
,
0
,
sizeof
(
*
fsinfo
)
);
fsinfo
->
magic1
=
VDISK_FSINFO_MAGIC1
;
fsinfo
->
magic2
=
VDISK_FSINFO_MAGIC2
;
fsinfo
->
next_free
=
VDISK_FSINFO_NEXT_FREE
;
fsinfo
->
magic3
=
VDISK_FSINFO_MAGIC3
;
}
/**
* Read from virtual FAT
*
* @v lba Starting LBA
* @v count Number of blocks to read
* @v data Data buffer
*/
static
void
vdisk_fat
(
uint64_t
lba
,
unsigned
int
count
,
void
*
data
)
{
uint32_t
*
next
=
data
;
uint32_t
start
;
uint32_t
end
;
uint32_t
file_end_marker
;
unsigned
int
i
;
/* Calculate window within FAT */
start
=
(
(
lba
-
VDISK_FAT_LBA
)
*
(
VDISK_SECTOR_SIZE
/
sizeof
(
*
next
)
)
);
end
=
(
start
+
(
count
*
(
VDISK_SECTOR_SIZE
/
sizeof
(
*
next
)
)
)
);
next
-=
start
;
/* Start by marking each cluster as chaining to the next */
for
(
i
=
start
;
i
<
end
;
i
++
)
next
[
i
]
=
(
i
+
1
);
/* Add first-sector special values, if applicable */
if
(
start
==
0
)
{
next
[
0
]
=
(
(
VDISK_FAT_END_MARKER
&
~
0xff
)
|
VDISK_VBR_MEDIA
);
for
(
i
=
1
;
i
<
(
VDISK_SECTOR_SIZE
/
sizeof
(
*
next
)
);
i
++
)
next
[
i
]
=
VDISK_FAT_END_MARKER
;
}
/* Add end-of-file markers, if applicable */
for
(
i
=
0
;
i
<
VDISK_MAX_FILES
;
i
++
)
{
if
(
vdisk_files
[
i
].
read
)
{
file_end_marker
=
(
VDISK_FILE_CLUSTER
(
i
)
+
(
(
vdisk_files
[
i
].
xlen
-
1
)
/
VDISK_CLUSTER_SIZE
)
);
if
(
(
file_end_marker
>=
start
)
&&
(
file_end_marker
<
end
)
)
{
next
[
file_end_marker
]
=
VDISK_FAT_END_MARKER
;
}
}
}
}
/**
* Initialise empty directory
*
* @v dir Virtual directory
* @ret dirent Starting (i.e. final) directory entry
*/
static
union
vdisk_directory_entry
*
vdisk_empty_dir
(
struct
vdisk_directory
*
dir
)
{
unsigned
int
i
;
/* Mark all entries as present and deleted */
memset
(
dir
,
0
,
sizeof
(
*
dir
)
);
for
(
i
=
0
;
i
<
VDISK_DIRENT_PER_SECTOR
;
i
++
)
{
dir
->
entry
[
i
].
deleted
=
VDISK_DIRENT_DELETED
;
}
return
&
dir
->
entry
[
VDISK_DIRENT_PER_SECTOR
-
1
];
}
/**
* Construct directory entry
*
* @v dirent Starting (i.e. final) directory entry
* @v name File name
* @v len File length
* @v attr File attributes
* @v cluster File starting cluster
* @ret next Next available directory entry
*/
static
union
vdisk_directory_entry
*
vdisk_directory_entry
(
union
vdisk_directory_entry
*
dirent
,
const
char
*
name
,
size_t
len
,
unsigned
int
attr
,
uint32_t
cluster
)
{
union
vdisk_directory_entry
*
dos
=
dirent
;
union
vdisk_directory_entry
*
lfn
=
(
dos
-
1
);
uint8_t
*
checksum_data
;
uint8_t
checksum
;
unsigned
int
sequence
;
uint16_t
*
lfn_char
;
char
c
;
unsigned
int
i
;
/* Populate directory entry (with invalid 8.3 filename) */
memset
(
dos
->
dos
.
filename
.
raw
,
' '
,
sizeof
(
dos
->
dos
.
filename
.
raw
)
);
dos
->
dos
.
attr
=
attr
;
dos
->
dos
.
size
=
len
;
dos
->
dos
.
cluster_high
=
(
cluster
>>
16
);
dos
->
dos
.
cluster_low
=
(
cluster
&
0xffff
);
/* Calculate checksum of 8.3 filename */
checksum
=
0
;
checksum_data
=
dos
->
dos
.
filename
.
raw
;
for
(
i
=
0
;
i
<
sizeof
(
dos
->
dos
.
filename
.
raw
)
;
i
++
)
{
checksum
=
(
(
(
(
checksum
&
1
)
<<
7
)
|
(
checksum
>>
1
)
)
+
*
(
checksum_data
++
)
);
}
/* Construct long filename record */
lfn_char
=
&
lfn
->
lfn
.
name_1
[
0
];
sequence
=
1
;
while
(
1
)
{
/* Initialise long filename, if necessary */
if
(
lfn
->
lfn
.
attr
!=
VDISK_LFN_ATTR
)
{
lfn
->
lfn
.
sequence
=
sequence
++
;
memset
(
lfn
->
lfn
.
name_1
,
0xff
,
sizeof
(
lfn
->
lfn
.
name_1
)
);
lfn
->
lfn
.
attr
=
VDISK_LFN_ATTR
;
lfn
->
lfn
.
checksum
=
checksum
;
memset
(
lfn
->
lfn
.
name_2
,
0xff
,
sizeof
(
lfn
->
lfn
.
name_2
)
);
memset
(
lfn
->
lfn
.
name_3
,
0xff
,
sizeof
(
lfn
->
lfn
.
name_3
)
);
}
/* Add character to long filename */
c
=
*
(
name
++
);
*
lfn_char
=
c
;
if
(
!
c
)
break
;
/* Move to next character within long filename */
if
(
lfn_char
==
&
lfn
->
lfn
.
name_1
[
4
]
)
{
lfn_char
=
&
lfn
->
lfn
.
name_2
[
0
];
}
else
if
(
lfn_char
==
&
lfn
->
lfn
.
name_2
[
5
]
)
{
lfn_char
=
&
lfn
->
lfn
.
name_3
[
0
];
}
else
if
(
lfn_char
==
&
lfn
->
lfn
.
name_3
[
1
]
)
{
lfn
--
;
lfn_char
=
&
lfn
->
lfn
.
name_1
[
0
];
}
else
{
lfn_char
++
;
}
}
lfn
->
lfn
.
sequence
|=
VDISK_LFN_END
;
return
(
lfn
-
1
);
}
/**
* Read subdirectories from virtual root directory
*
* @v lba Starting LBA
* @v count Number of blocks to read
* @v data Data buffer
*/
static
void
vdisk_root
(
uint64_t
lba
__unused
,
unsigned
int
count
__unused
,
void
*
data
)
{
struct
vdisk_directory
*
dir
=
data
;
union
vdisk_directory_entry
*
dirent
;
/* Construct subdirectories */
dirent
=
vdisk_empty_dir
(
dir
);
dirent
=
vdisk_directory_entry
(
dirent
,
"BOOT"
,
0
,
VDISK_DIRECTORY
,
VDISK_BOOT_CLUSTER
);
dirent
=
vdisk_directory_entry
(
dirent
,
"SOURCES"
,
0
,
VDISK_DIRECTORY
,
VDISK_SOURCES_CLUSTER
);
dirent
=
vdisk_directory_entry
(
dirent
,
"EFI"
,
0
,
VDISK_DIRECTORY
,
VDISK_EFI_CLUSTER
);
}
/**
* Read subdirectories from virtual boot directory
*
* @v lba Starting LBA
* @v count Number of blocks to read
* @v data Data buffer
*/
static
void
vdisk_boot
(
uint64_t
lba
__unused
,
unsigned
int
count
__unused
,
void
*
data
)
{
struct
vdisk_directory
*
dir
=
data
;
union
vdisk_directory_entry
*
dirent
;
/* Construct subdirectories */
dirent
=
vdisk_empty_dir
(
dir
);
dirent
=
vdisk_directory_entry
(
dirent
,
"FONTS"
,
0
,
VDISK_DIRECTORY
,
VDISK_FONTS_CLUSTER
);
dirent
=
vdisk_directory_entry
(
dirent
,
"RESOURCES"
,
0
,
VDISK_DIRECTORY
,
VDISK_RESOURCES_CLUSTER
);
}
/**
* Read subdirectories from virtual sources directory
*
* @v lba Starting LBA
* @v count Number of blocks to read
* @v data Data buffer
*/
static
void
vdisk_sources
(
uint64_t
lba
__unused
,
unsigned
int
count
__unused
,
void
*
data
)
{
struct
vdisk_directory
*
dir
=
data
;
/* Construct subdirectories */
vdisk_empty_dir
(
dir
);
}
/**
* Read subdirectories from virtual fonts directory
*
* @v lba Starting LBA
* @v count Number of blocks to read
* @v data Data buffer
*/
static
void
vdisk_fonts
(
uint64_t
lba
__unused
,
unsigned
int
count
__unused
,
void
*
data
)
{
struct
vdisk_directory
*
dir
=
data
;
/* Construct subdirectories */
vdisk_empty_dir
(
dir
);
}
/**
* Read subdirectories from virtual resources directory
*
* @v lba Starting LBA
* @v count Number of blocks to read
* @v data Data buffer
*/
static
void
vdisk_resources
(
uint64_t
lba
__unused
,
unsigned
int
count
__unused
,
void
*
data
)
{
struct
vdisk_directory
*
dir
=
data
;
/* Construct subdirectories */
vdisk_empty_dir
(
dir
);
}
/**
* Read subdirectories from virtual EFI directory
*
* @v lba Starting LBA
* @v count Number of blocks to read
* @v data Data buffer
*/
static
void
vdisk_efi
(
uint64_t
lba
__unused
,
unsigned
int
count
__unused
,
void
*
data
)
{
struct
vdisk_directory
*
dir
=
data
;
union
vdisk_directory_entry
*
dirent
;
/* Construct subdirectories */
dirent
=
vdisk_empty_dir
(
dir
);
dirent
=
vdisk_directory_entry
(
dirent
,
"BOOT"
,
0
,
VDISK_DIRECTORY
,
VDISK_BOOT_CLUSTER
);
dirent
=
vdisk_directory_entry
(
dirent
,
"MICROSOFT"
,
0
,
VDISK_DIRECTORY
,
VDISK_MICROSOFT_CLUSTER
);
}
/**
* Read subdirectories from virtual Microsoft directory
*
* @v lba Starting LBA
* @v count Number of blocks to read
* @v data Data buffer
*/
static
void
vdisk_microsoft
(
uint64_t
lba
__unused
,
unsigned
int
count
__unused
,
void
*
data
)
{
struct
vdisk_directory
*
dir
=
data
;
union
vdisk_directory_entry
*
dirent
;
/* Construct subdirectories */
dirent
=
vdisk_empty_dir
(
dir
);
dirent
=
vdisk_directory_entry
(
dirent
,
"BOOT"
,
0
,
VDISK_DIRECTORY
,
VDISK_BOOT_CLUSTER
);
}
/**
* Read files from virtual directory
*
* @v lba Starting LBA
* @v count Number of blocks to read
* @v data Data buffer
*/
static
void
vdisk_dir_files
(
uint64_t
lba
,
unsigned
int
count
,
void
*
data
)
{
struct
vdisk_directory
*
dir
;
union
vdisk_directory_entry
*
dirent
;
struct
vdisk_file
*
file
;
unsigned
int
idx
;
for
(
;
count
;
lba
++
,
count
--
,
data
+=
VDISK_SECTOR_SIZE
)
{
/* Initialise directory */
dir
=
data
;
vdisk_empty_dir
(
dir
);
dirent
=
&
dir
->
entry
[
VDISK_DIRENT_PER_SECTOR
-
1
];
/* Identify file */
idx
=
VDISK_FILE_DIRENT_IDX
(
lba
);
assert
(
idx
<
(
sizeof
(
vdisk_files
)
/
sizeof
(
vdisk_files
[
0
]
)
)
);
file
=
&
vdisk_files
[
idx
];
if
(
!
file
->
read
)
continue
;
/* Populate directory entry */
vdisk_directory_entry
(
dirent
,
file
->
name
,
file
->
xlen
,
VDISK_READ_ONLY
,
VDISK_FILE_CLUSTER
(
idx
)
);
}
}
/**
* Read from virtual file (or empty space)
*
* @v lba Starting LBA
* @v count Number of blocks to read
* @v data Data buffer
*/
static
void
vdisk_file
(
uint64_t
lba
,
unsigned
int
count
,
void
*
data
)
{
struct
vdisk_file
*
file
;
size_t
offset
;
size_t
len
;
size_t
copy_len
;
size_t
pad_len
;
size_t
patch_len
;
/* Construct file portion */
file
=
&
vdisk_files
[
VDISK_FILE_IDX
(
lba
)
];
offset
=
VDISK_FILE_OFFSET
(
lba
);
len
=
(
count
*
VDISK_SECTOR_SIZE
);
/* Copy any initialised-data portion */
copy_len
=
(
(
offset
<
file
->
len
)
?
(
file
->
len
-
offset
)
:
0
);
if
(
copy_len
>
len
)
copy_len
=
len
;
if
(
copy_len
)
file
->
read
(
file
,
data
,
offset
,
copy_len
);
/* Zero any uninitialised-data portion */
pad_len
=
(
len
-
copy_len
);
memset
(
(
data
+
copy_len
),
0
,
pad_len
);
/* Patch any applicable portion */
patch_len
=
(
(
offset
<
file
->
xlen
)
?
(
file
->
xlen
-
offset
)
:
0
);
if
(
patch_len
>
len
)
patch_len
=
len
;
if
(
file
->
patch
)
file
->
patch
(
file
,
data
,
offset
,
patch_len
);
}
/** A virtual disk region */
struct
vdisk_region
{
/** Name */
const
char
*
name
;
/** Starting LBA */
uint64_t
lba
;
/** Number of blocks */
unsigned
int
count
;
/**
* Build data from this region
*
* @v start Starting LBA
* @v count Number of blocks to read
* @v data Data buffer
*/
void
(
*
build
)
(
uint64_t
lba
,
unsigned
int
count
,
void
*
data
);
};
/** Define a virtual disk region */
#define VDISK_REGION( _name, _build, _lba, _count ) { \
.name = _name, \
.lba = _lba, \
.count = _count, \
.build = _build, \
}
/** Define a virtual disk directory region */
#define VDISK_DIRECTORY_REGION( _name, _build_subdirs, _lba ) { \
.name = _name " subdirs", \
.lba = _lba, \
.count = 1, \
.build = _build_subdirs, \
}, { \
.name = _name " files", \
.lba = ( _lba + 1 ), \
.count = ( VDISK_CLUSTER_COUNT - 1 ), \
.build = vdisk_dir_files, \
}
/** Virtual disk regions */
static
struct
vdisk_region
vdisk_regions
[]
=
{
VDISK_REGION
(
"MBR"
,
vdisk_mbr
,
VDISK_MBR_LBA
,
VDISK_MBR_COUNT
),
VDISK_REGION
(
"VBR"
,
vdisk_vbr
,
VDISK_VBR_LBA
,
VDISK_VBR_COUNT
),
VDISK_REGION
(
"FSInfo"
,
vdisk_fsinfo
,
VDISK_FSINFO_LBA
,
VDISK_FSINFO_COUNT
),
VDISK_REGION
(
"VBR Backup"
,
vdisk_vbr
,
VDISK_BACKUP_VBR_LBA
,
VDISK_BACKUP_VBR_COUNT
),
VDISK_REGION
(
"FAT"
,
vdisk_fat
,
VDISK_FAT_LBA
,
VDISK_FAT_COUNT
),
VDISK_DIRECTORY_REGION
(
"Root"
,
vdisk_root
,
VDISK_ROOT_LBA
),
VDISK_DIRECTORY_REGION
(
"Boot"
,
vdisk_boot
,
VDISK_BOOT_LBA
),
VDISK_DIRECTORY_REGION
(
"Sources"
,
vdisk_sources
,
VDISK_SOURCES_LBA
),
VDISK_DIRECTORY_REGION
(
"Fonts"
,
vdisk_fonts
,
VDISK_FONTS_LBA
),
VDISK_DIRECTORY_REGION
(
"Resources"
,
vdisk_resources
,
VDISK_RESOURCES_LBA
),
VDISK_DIRECTORY_REGION
(
"EFI"
,
vdisk_efi
,
VDISK_EFI_LBA
),
VDISK_DIRECTORY_REGION
(
"Microsoft"
,
vdisk_microsoft
,
VDISK_MICROSOFT_LBA
),
};
/**
* Read from virtual disk
*
* @v lba Starting LBA
* @v count Number of blocks to read
* @v data Data buffer
*/
void
vdisk_read
(
uint64_t
lba
,
unsigned
int
count
,
void
*
data
)
{
struct
vdisk_region
*
region
;
void
(
*
build
)
(
uint64_t
lba
,
unsigned
int
count
,
void
*
data
);
const
char
*
name
;
uint64_t
start
=
lba
;
uint64_t
end
=
(
lba
+
count
);
uint64_t
frag_start
=
start
;
uint64_t
frag_end
;
int
file_idx
;
uint64_t
file_end
;
uint64_t
region_start
;
uint64_t
region_end
;
unsigned
int
frag_count
;
unsigned
int
i
;
DBG2
(
"Read to %p from %#llx+%#x: "
,
data
,
lba
,
count
);
do
{
/* Initialise fragment to fill remaining space */
frag_end
=
end
;
name
=
NULL
;
build
=
NULL
;
/* Truncate fragment and generate data */
file_idx
=
VDISK_FILE_IDX
(
frag_start
);
if
(
file_idx
>=
0
)
{
/* Truncate fragment to end of file */
file_end
=
VDISK_FILE_LBA
(
file_idx
+
1
);
if
(
frag_end
>
file_end
)
frag_end
=
file_end
;
/* Generate data from file */
if
(
file_idx
<
VDISK_MAX_FILES
)
{
name
=
vdisk_files
[
file_idx
].
name
;
build
=
vdisk_file
;
}
}
else
{
/* Truncate fragment to region boundaries */
for
(
i
=
0
;
i
<
(
sizeof
(
vdisk_regions
)
/
sizeof
(
vdisk_regions
[
0
]
)
);
i
++
){
region
=
&
vdisk_regions
[
i
];
region_start
=
region
->
lba
;
region_end
=
(
region_start
+
region
->
count
);
/* Avoid crossing start of any region */
if
(
(
frag_start
<
region_start
)
&&
(
frag_end
>
region_start
)
){
frag_end
=
region_start
;
}
/* Ignore unless we overlap with this region */
if
(
(
frag_start
>=
region_end
)
||
(
frag_end
<=
region_start
)
)
{
continue
;
}
/* Avoid crossing end of region */
if
(
frag_end
>
region_end
)
frag_end
=
region_end
;
/* Found a suitable region */
name
=
region
->
name
;
build
=
region
->
build
;
break
;
}
}
/* Generate data from this region */
frag_count
=
(
frag_end
-
frag_start
);
DBG2
(
"%s%s (%#x)"
,
(
(
frag_start
==
start
)
?
""
:
", "
),
(
name
?
name
:
"empty"
),
frag_count
);
if
(
build
)
{
build
(
frag_start
,
frag_count
,
data
);
}
else
{
memset
(
data
,
0
,
(
frag_count
*
VDISK_SECTOR_SIZE
)
);
}
/* Move to next fragment */
frag_start
+=
frag_count
;
data
+=
(
frag_count
*
VDISK_SECTOR_SIZE
);
}
while
(
frag_start
!=
end
);
DBG2
(
"
\n
"
);
}
/**
* Add file to virtual disk
*
* @v name Name
* @v opaque Opaque token
* @v len Length
* @v read Read data method
* @ret file Virtual file
*/
struct
vdisk_file
*
vdisk_add_file
(
const
char
*
name
,
void
*
opaque
,
size_t
len
,
void
(
*
read
)
(
struct
vdisk_file
*
file
,
void
*
data
,
size_t
offset
,
size_t
len
)
)
{
static
unsigned
int
index
=
0
;
struct
vdisk_file
*
file
;
/* Sanity check */
if
(
index
>=
VDISK_MAX_FILES
)
die
(
"Too many files
\n
"
);
/* Store file */
file
=
&
vdisk_files
[
index
++
];
snprintf
(
file
->
name
,
sizeof
(
file
->
name
),
"%s"
,
name
);
file
->
opaque
=
opaque
;
file
->
len
=
len
;
file
->
xlen
=
len
;
file
->
read
=
read
;
DBG
(
"Using %s via %p len %#zx
\n
"
,
file
->
name
,
file
->
opaque
,
file
->
len
);
return
file
;
}
/**
* Patch virtual file
*
* @v file Virtual file
* @v patch Patch method
*/
void
vdisk_patch_file
(
struct
vdisk_file
*
file
,
void
(
*
patch
)
(
struct
vdisk_file
*
file
,
void
*
data
,
size_t
offset
,
size_t
len
)
)
{
/* Record patch method */
file
->
patch
=
patch
;
/* Allow patch method to update file length */
patch
(
file
,
NULL
,
0
,
0
);
}
wimboot/wimboot-2.7.3/src/vdisk.h
0 → 100644
View file @
93996cf7
#ifndef _VDISK_H
#define _VDISK_H
/*
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
* @file
*
* Virtual disk emulation
*
*/
#include <stdint.h>
/** Number of cylinders */
#define VDISK_CYLINDERS 1024
/* Maximum possible */
/** Number of heads */
#define VDISK_HEADS 255
/** Number of sectors per track */
#define VDISK_SECTORS_PER_TRACK 63
/** Sector size (in bytes) */
#define VDISK_SECTOR_SIZE 512
/** Partition start LBA */
#define VDISK_PARTITION_LBA 128
/** Cluster size (in sectors) */
#define VDISK_CLUSTER_COUNT 64
/** Cluster size (in bytes) */
#define VDISK_CLUSTER_SIZE ( VDISK_CLUSTER_COUNT * VDISK_SECTOR_SIZE )
/** Number of clusters */
#define VDISK_CLUSTERS 0x03ffc000ULL
/* Fill 2TB disk */
/** Maximum number of virtual files
*
* The total number of files must be strictly less than the number of
* sectors per cluster.
*/
#define VDISK_MAX_FILES ( VDISK_CLUSTER_COUNT - 1 )
/** Maximum file size (in sectors) */
#define VDISK_FILE_COUNT 0x800000UL
/* max for 32-bit address space */
/** Maximum file size (in clusters) */
#define VDISK_FILE_CLUSTERS ( VDISK_FILE_COUNT / VDISK_CLUSTER_COUNT )
/** File starting LBA */
#define VDISK_FILE_LBA( idx ) ( ( (idx) + 1 ) * VDISK_FILE_COUNT )
/** File index from LBA */
#define VDISK_FILE_IDX( lba ) ( ( (lba) / VDISK_FILE_COUNT ) - 1 )
/** File offset (in bytes) from LBA */
#define VDISK_FILE_OFFSET( lba ) \
( ( (lba) % VDISK_FILE_COUNT ) * VDISK_SECTOR_SIZE )
/** File index from directory entry LBA */
#define VDISK_FILE_DIRENT_IDX( lba ) ( ( (lba) - 1 ) % VDISK_CLUSTER_COUNT )
/** Number of sectors allocated for FAT */
#define VDISK_SECTORS_PER_FAT \
( ( ( VDISK_CLUSTERS * sizeof ( uint32_t ) + \
VDISK_CLUSTER_SIZE - 1 ) / VDISK_CLUSTER_SIZE ) \
* VDISK_CLUSTER_COUNT )
/** Number of reserved sectors */
#define VDISK_RESERVED_COUNT VDISK_CLUSTER_COUNT
/** Starting cluster number for file */
#define VDISK_FILE_CLUSTER( idx ) \
( ( ( ( VDISK_FILE_COUNT - VDISK_PARTITION_LBA - \
VDISK_RESERVED_COUNT - VDISK_SECTORS_PER_FAT ) / \
VDISK_CLUSTER_COUNT ) + 2 ) + \
( (idx) * VDISK_FILE_CLUSTERS ) )
/** Total number of sectors within partition */
#define VDISK_PARTITION_COUNT \
( VDISK_RESERVED_COUNT + VDISK_SECTORS_PER_FAT + \
( VDISK_CLUSTERS * VDISK_CLUSTER_COUNT ) )
/** Number of sectors */
#define VDISK_COUNT ( VDISK_PARTITION_LBA + VDISK_PARTITION_COUNT )
/** Calculate sector from cluster */
#define VDISK_CLUSTER_SECTOR( cluster ) \
( ( ( (cluster) - 2 ) * VDISK_CLUSTER_COUNT ) + \
VDISK_RESERVED_COUNT + VDISK_SECTORS_PER_FAT )
/*****************************************************************************
*
* Master Boot Record
*
*****************************************************************************
*/
/** Master Boot Record LBA */
#define VDISK_MBR_LBA 0x00000000
/** Master Boot Record sector count */
#define VDISK_MBR_COUNT 1
/** Partition table entry */
struct
vdisk_partition
{
/** Bootable flag */
uint8_t
bootable
;
/** C/H/S start address */
uint8_t
chs_start
[
3
];
/** System indicator (partition type) */
uint8_t
type
;
/** C/H/S end address */
uint8_t
chs_end
[
3
];
/** Linear start address */
uint32_t
start
;
/** Linear length */
uint32_t
length
;
}
__attribute__
((
packed
));
/** Master Boot Record */
struct
vdisk_mbr
{
/** Code area */
uint8_t
code
[
440
];
/** Disk signature */
uint32_t
signature
;
/** Padding */
uint8_t
pad
[
2
];
/** Partition table */
struct
vdisk_partition
partitions
[
4
];
/** 0x55aa signature */
uint16_t
magic
;
}
__attribute__
((
packed
));
/** MBR boot partition indiciator */
#define VDISK_MBR_BOOTABLE 0x80
/** MBR type indicator for FAT32 */
#define VDISK_MBR_TYPE_FAT32 0x0c
/** MBR signature */
#define VDISK_MBR_SIGNATURE 0xc0ffeeee
/** MBR magic */
#define VDISK_MBR_MAGIC 0xaa55
/*****************************************************************************
*
* Volume Boot Record
*
*****************************************************************************
*/
/** Volume Boot Record LBA */
#define VDISK_VBR_LBA VDISK_PARTITION_LBA
/** Volume Boot Record sector count */
#define VDISK_VBR_COUNT 1
/** Volume Boot Record */
struct
vdisk_vbr
{
/** Jump instruction */
uint8_t
jump
[
3
];
/** OEM identifier */
char
oemid
[
8
];
/** Number of bytes per sector */
uint16_t
bytes_per_sector
;
/** Number of sectors per cluster */
uint8_t
sectors_per_cluster
;
/** Number of reserved sectors */
uint16_t
reserved_sectors
;
/** Number of FATs */
uint8_t
fats
;
/** Number of root directory entries (FAT12/FAT16 only) */
uint16_t
root_directory_entries
;
/** Total number of sectors (0 if more than 65535) */
uint16_t
sectors_short
;
/** Media descriptor type */
uint8_t
media
;
/** Number of sectors per FAT (FAT12/FAT16 only) */
uint16_t
sectors_per_fat_short
;
/** Number of sectors per track */
uint16_t
sectors_per_track
;
/** Number of heads */
uint16_t
heads
;
/** Number of hidden sectors (i.e. LBA of start of partition) */
uint32_t
hidden_sectors
;
/** Total number of sectors */
uint32_t
sectors
;
/* FAT32-specific fields */
/** Sectors per FAT */
uint32_t
sectors_per_fat
;
/** Flags */
uint16_t
flags
;
/** FAT version number */
uint16_t
version
;
/** Root directory cluster */
uint32_t
root
;
/** FSInfo sector */
uint16_t
fsinfo
;
/** Backup boot sector */
uint16_t
backup
;
/** Reserved */
uint8_t
reserved
[
12
];
/** Drive number */
uint8_t
drive
;
/** Windows NT flags */
uint8_t
nt_flags
;
/** Signature */
uint8_t
signature
;
/** Volume ID serial */
uint32_t
serial
;
/** Label (space-padded) */
char
label
[
11
];
/** System identifier */
char
system
[
8
];
/** Boot code */
uint8_t
code
[
420
];
/** 0x55aa signature */
uint16_t
magic
;
}
__attribute__
((
packed
));
/** VBR jump instruction
*
* bootmgr.exe will actually fail unless this is present. Someone
* must read specification documents without bothering to understand
* what's really happening.
*/
#define VDISK_VBR_JUMP_WTF_MS 0xe9
/** VBR OEM ID */
#define VDISK_VBR_OEMID "wimboot\0"
/** VBR media type */
#define VDISK_VBR_MEDIA 0xf8
/** VBR signature */
#define VDISK_VBR_SIGNATURE 0x29
/** VBR serial number */
#define VDISK_VBR_SERIAL 0xf00df00d
/** VBR label */
#define VDISK_VBR_LABEL "wimboot "
/** VBR system identifier */
#define VDISK_VBR_SYSTEM "FAT32 "
/** VBR magic */
#define VDISK_VBR_MAGIC 0xaa55
/*****************************************************************************
*
* FSInfo
*
*****************************************************************************
*/
/** FSInfo sector */
#define VDISK_FSINFO_SECTOR 0x00000001
/** FSInfo LBA */
#define VDISK_FSINFO_LBA ( VDISK_VBR_LBA + VDISK_FSINFO_SECTOR )
/** FSInfo sector count */
#define VDISK_FSINFO_COUNT 1
/** FSInfo */
struct
vdisk_fsinfo
{
/** First signature */
uint32_t
magic1
;
/** Reserved */
uint8_t
reserved_1
[
480
];
/** Second signature */
uint32_t
magic2
;
/** Free cluster count */
uint32_t
free_count
;
/** Next free cluster */
uint32_t
next_free
;
/** Reserved */
uint8_t
reserved_2
[
12
];
/** Third signature */
uint32_t
magic3
;
}
__attribute__
((
packed
));
/** FSInfo first signature */
#define VDISK_FSINFO_MAGIC1 0x41615252
/** FSInfo second signature */
#define VDISK_FSINFO_MAGIC2 0x61417272
/** FSInfo next free cluster */
#define VDISK_FSINFO_NEXT_FREE 0xffffffff
/* No free clusters */
/** FSInfo third signature */
#define VDISK_FSINFO_MAGIC3 0xaa550000
/*****************************************************************************
*
* Backup Volume Boot Record
*
*****************************************************************************
*/
/** Backup Volume Boot Record sector */
#define VDISK_BACKUP_VBR_SECTOR 0x00000006
/** Backup Volume Boot Record LBA */
#define VDISK_BACKUP_VBR_LBA ( VDISK_VBR_LBA + VDISK_BACKUP_VBR_SECTOR )
/** Backup Volume Boot Record sector count */
#define VDISK_BACKUP_VBR_COUNT 1
/*****************************************************************************
*
* File Allocation Table
*
*****************************************************************************
*/
/** FAT sector */
#define VDISK_FAT_SECTOR VDISK_RESERVED_COUNT
/** FAT LBA */
#define VDISK_FAT_LBA ( VDISK_VBR_LBA + VDISK_FAT_SECTOR )
/** FAT sector count */
#define VDISK_FAT_COUNT VDISK_SECTORS_PER_FAT
/** FAT end marker */
#define VDISK_FAT_END_MARKER 0x0ffffff8
/*****************************************************************************
*
* Directory entries
*
*****************************************************************************
*/
/** An 8.3 filename record */
struct
vdisk_short_filename
{
/** Filename */
union
{
/** Structured 8.3 base name and extension */
struct
{
/** Base name */
char
base
[
8
];
/** Extension */
char
ext
[
3
];
}
__attribute__
((
packed
));
/** Raw bytes */
uint8_t
raw
[
11
];
}
filename
;
/** Attributes */
uint8_t
attr
;
/** Reserved */
uint8_t
reserved
;
/** Creation time in tenths of a second */
uint8_t
created_deciseconds
;
/** Creation time (HMS packed) */
uint16_t
created_time
;
/** Creation date (YMD packed) */
uint16_t
created_date
;
/** Last accessed date (YMD packed) */
uint16_t
accessed_date
;
/** High 16 bits of starting cluster number */
uint16_t
cluster_high
;
/** Modification time (HMS packed) */
uint16_t
modified_time
;
/** Modification date (YMD packed) */
uint16_t
modified_date
;
/** Low 16 bits of starting cluster number */
uint16_t
cluster_low
;
/** Size */
uint32_t
size
;
}
__attribute__
((
packed
));
/** A long filename record */
struct
vdisk_long_filename
{
/** Sequence number */
uint8_t
sequence
;
/** Name characters */
uint16_t
name_1
[
5
];
/** Attributes */
uint8_t
attr
;
/** Type */
uint8_t
type
;
/** Checksum of 8.3 name */
uint8_t
checksum
;
/** Name characters */
uint16_t
name_2
[
6
];
/** Reserved */
uint16_t
reserved
;
/** Name characters */
uint16_t
name_3
[
2
];
}
__attribute__
((
packed
));
/** Directory entry attributes */
enum
vdisk_directory_entry_attributes
{
VDISK_READ_ONLY
=
0x01
,
VDISK_HIDDEN
=
0x02
,
VDISK_SYSTEM
=
0x04
,
VDISK_VOLUME_LABEL
=
0x08
,
VDISK_DIRECTORY
=
0x10
,
};
/** Long filename end-of-sequence marker */
#define VDISK_LFN_END 0x40
/** Long filename attributes */
#define VDISK_LFN_ATTR \
( VDISK_READ_ONLY | VDISK_HIDDEN | VDISK_SYSTEM | VDISK_VOLUME_LABEL )
/** A directory entry */
union
vdisk_directory_entry
{
/** Deleted file marker */
uint8_t
deleted
;
/** 8.3 filename */
struct
vdisk_short_filename
dos
;
/** Long filename */
struct
vdisk_long_filename
lfn
;
}
__attribute__
((
packed
));
/** Magic marker for deleted files */
#define VDISK_DIRENT_DELETED 0xe5
/** Number of directory entries per sector */
#define VDISK_DIRENT_PER_SECTOR \
( VDISK_SECTOR_SIZE / \
sizeof ( union vdisk_directory_entry ) )
/** A directory sector */
struct
vdisk_directory
{
/** Entries */
union
vdisk_directory_entry
entry
[
VDISK_DIRENT_PER_SECTOR
];
}
__attribute__
((
packed
));
/*****************************************************************************
*
* Root directory
*
*****************************************************************************
*/
/** Root directory cluster */
#define VDISK_ROOT_CLUSTER 2
/** Root directory sector */
#define VDISK_ROOT_SECTOR VDISK_CLUSTER_SECTOR ( VDISK_ROOT_CLUSTER )
/** Root directory LBA */
#define VDISK_ROOT_LBA ( VDISK_VBR_LBA + VDISK_ROOT_SECTOR )
/*****************************************************************************
*
* Boot directory
*
*****************************************************************************
*/
/** Boot directory cluster */
#define VDISK_BOOT_CLUSTER 3
/** Boot directory sector */
#define VDISK_BOOT_SECTOR VDISK_CLUSTER_SECTOR ( VDISK_BOOT_CLUSTER )
/** Boot directory LBA */
#define VDISK_BOOT_LBA ( VDISK_VBR_LBA + VDISK_BOOT_SECTOR )
/*****************************************************************************
*
* Sources directory
*
*****************************************************************************
*/
/** Sources directory cluster */
#define VDISK_SOURCES_CLUSTER 4
/** Sources directory sector */
#define VDISK_SOURCES_SECTOR VDISK_CLUSTER_SECTOR ( VDISK_SOURCES_CLUSTER )
/** Sources directory LBA */
#define VDISK_SOURCES_LBA ( VDISK_VBR_LBA + VDISK_SOURCES_SECTOR )
/*****************************************************************************
*
* Fonts directory
*
*****************************************************************************
*/
/** Fonts directory cluster */
#define VDISK_FONTS_CLUSTER 5
/** Fonts directory sector */
#define VDISK_FONTS_SECTOR VDISK_CLUSTER_SECTOR ( VDISK_FONTS_CLUSTER )
/** Fonts directory LBA */
#define VDISK_FONTS_LBA ( VDISK_VBR_LBA + VDISK_FONTS_SECTOR )
/*****************************************************************************
*
* Resources directory
*
*****************************************************************************
*/
/** Resources directory cluster */
#define VDISK_RESOURCES_CLUSTER 6
/** Resources directory sector */
#define VDISK_RESOURCES_SECTOR VDISK_CLUSTER_SECTOR ( VDISK_RESOURCES_CLUSTER )
/** Resources directory LBA */
#define VDISK_RESOURCES_LBA ( VDISK_VBR_LBA + VDISK_RESOURCES_SECTOR )
/*****************************************************************************
*
* EFI directory
*
*****************************************************************************
*/
/** EFI directory cluster */
#define VDISK_EFI_CLUSTER 7
/** EFI directory sector */
#define VDISK_EFI_SECTOR VDISK_CLUSTER_SECTOR ( VDISK_EFI_CLUSTER )
/** EFI directory LBA */
#define VDISK_EFI_LBA ( VDISK_VBR_LBA + VDISK_EFI_SECTOR )
/*****************************************************************************
*
* Microsoft directory
*
*****************************************************************************
*/
/** Microsoft directory cluster */
#define VDISK_MICROSOFT_CLUSTER 8
/** Microsoft directory sector */
#define VDISK_MICROSOFT_SECTOR VDISK_CLUSTER_SECTOR ( VDISK_MICROSOFT_CLUSTER )
/** Microsoft directory LBA */
#define VDISK_MICROSOFT_LBA ( VDISK_VBR_LBA + VDISK_MICROSOFT_SECTOR )
/*****************************************************************************
*
* Files
*
*****************************************************************************
*/
/** Maximum virtual filename length (excluding NUL) */
#define VDISK_NAME_LEN 31
/** A virtual file */
struct
vdisk_file
{
/** Filename */
char
name
[
VDISK_NAME_LEN
+
1
/* NUL */
];
/** Opaque token */
void
*
opaque
;
/** Length (excluding any zero-padding) */
size_t
len
;
/** Length (including any zero-padding) */
size_t
xlen
;
/** Read data
*
* @v file Virtual file
* @v data Data buffer
* @v offset Starting offset
* @v len Length
*/
void
(
*
read
)
(
struct
vdisk_file
*
file
,
void
*
data
,
size_t
offset
,
size_t
len
);
/** Patch data (optional)
*
* @v file Virtual file
* @v data Data buffer
* @v offset Starting offset
* @v len Length
*/
void
(
*
patch
)
(
struct
vdisk_file
*
file
,
void
*
data
,
size_t
offset
,
size_t
len
);
};
extern
struct
vdisk_file
vdisk_files
[
VDISK_MAX_FILES
];
extern
void
vdisk_read
(
uint64_t
lba
,
unsigned
int
count
,
void
*
data
);
extern
struct
vdisk_file
*
vdisk_add_file
(
const
char
*
name
,
void
*
opaque
,
size_t
len
,
void
(
*
read
)
(
struct
vdisk_file
*
file
,
void
*
data
,
size_t
offset
,
size_t
len
)
);
extern
void
vdisk_patch_file
(
struct
vdisk_file
*
file
,
void
(
*
patch
)
(
struct
vdisk_file
*
file
,
void
*
data
,
size_t
offset
,
size_t
len
)
);
#endif
/* _VDISK_H */
wimboot/wimboot-2.7.3/src/vsprintf.c
0 → 100644
View file @
93996cf7
/*
* Quick and dirty wrapper around iPXE's unmodified vsprintf.c
*
*/
#include <stdint.h>
#include <string.h>
#include "wimboot.h"
#define FILE_LICENCE(x)
#include "ipxe/vsprintf.c"
wimboot/wimboot-2.7.3/src/wchar.h
0 → 100644
View file @
93996cf7
#ifndef _WCHAR_H
#define _WCHAR_H
/*
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
* @file
*
* Wide characters
*
*/
#include <stdint.h>
typedef
void
mbstate_t
;
/**
* Convert wide character to multibyte sequence
*
* @v buf Buffer
* @v wc Wide character
* @v ps Shift state
* @ret len Number of characters written
*
* This is a stub implementation, sufficient to handle basic ASCII
* characters.
*/
static
inline
size_t
wcrtomb
(
char
*
buf
,
wchar_t
wc
,
mbstate_t
*
ps
__attribute__
((
unused
))
)
{
*
buf
=
wc
;
return
1
;
}
extern
int
wcscasecmp
(
const
wchar_t
*
str1
,
const
wchar_t
*
str2
);
extern
size_t
wcslen
(
const
wchar_t
*
str
);
extern
wchar_t
*
wcschr
(
const
wchar_t
*
str
,
wchar_t
c
);
extern
char
*
strchr
(
const
char
*
str
,
char
c
);
#endif
/* _WCHAR_H */
wimboot/wimboot-2.7.3/src/wctype.h
0 → 100644
View file @
93996cf7
#ifndef _WCTYPE_H
#define _WCTYPE_H
/*
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
* @file
*
* Wide character types
*
* We don't actually care about wide characters. Internationalisation
* is a user interface concern, and has absolutely no place in the
* boot process. However, UEFI uses wide characters and so we have to
* at least be able to handle the ASCII subset of UCS-2.
*
*/
#include <ctype.h>
static
inline
int
iswlower
(
wint_t
c
)
{
return
islower
(
c
);
}
static
inline
int
iswupper
(
wint_t
c
)
{
return
isupper
(
c
);
}
static
inline
int
towupper
(
wint_t
c
)
{
return
toupper
(
c
);
}
static
inline
int
iswspace
(
wint_t
c
)
{
return
isspace
(
c
);
}
#endif
/* _WCTYPE_H */
wimboot/wimboot-2.7.3/src/wim.c
0 → 100644
View file @
93996cf7
/*
* Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
* @file
*
* WIM images
*
*/
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <wchar.h>
#include <assert.h>
#include "wimboot.h"
#include "vdisk.h"
#include "lzx.h"
#include "wim.h"
/** WIM chunk buffer */
static
struct
wim_chunk_buffer
wim_chunk_buffer
;
/**
* Get WIM header
*
* @v file Virtual file
* @v header WIM header to fill in
* @ret rc Return status code
*/
int
wim_header
(
struct
vdisk_file
*
file
,
struct
wim_header
*
header
)
{
/* Sanity check */
if
(
sizeof
(
*
header
)
>
file
->
len
)
{
DBG
(
"WIM file too short (%#zx bytes)
\n
"
,
file
->
len
);
return
-
1
;
}
/* Read WIM header */
file
->
read
(
file
,
header
,
0
,
sizeof
(
*
header
)
);
return
0
;
}
/**
* Get compressed chunk offset
*
* @v file Virtual file
* @v resource Resource
* @v chunk Chunk number
* @v offset Offset to fill in
* @ret rc Return status code
*/
static
int
wim_chunk_offset
(
struct
vdisk_file
*
file
,
struct
wim_resource_header
*
resource
,
unsigned
int
chunk
,
size_t
*
offset
)
{
size_t
zlen
=
(
resource
->
zlen__flags
&
WIM_RESHDR_ZLEN_MASK
);
unsigned
int
chunks
;
size_t
offset_offset
;
size_t
offset_len
;
size_t
chunks_len
;
union
{
uint32_t
offset_32
;
uint64_t
offset_64
;
}
u
;
/* Special case: zero-length files have no chunks */
if
(
!
resource
->
len
)
{
*
offset
=
0
;
return
0
;
}
/* Calculate chunk parameters */
chunks
=
(
(
resource
->
len
+
WIM_CHUNK_LEN
-
1
)
/
WIM_CHUNK_LEN
);
offset_len
=
(
(
resource
->
len
>
0xffffffffULL
)
?
sizeof
(
u
.
offset_64
)
:
sizeof
(
u
.
offset_32
)
);
chunks_len
=
(
(
chunks
-
1
)
*
offset_len
);
/* Sanity check */
if
(
chunks_len
>
zlen
)
{
DBG
(
"Resource too short for %d chunks
\n
"
,
chunks
);
return
-
1
;
}
/* Special case: chunk 0 has no offset field */
if
(
!
chunk
)
{
*
offset
=
chunks_len
;
return
0
;
}
/* Treat out-of-range chunks as being at the end of the
* resource, to allow for length calculation on the final
* chunk.
*/
if
(
chunk
>=
chunks
)
{
*
offset
=
zlen
;
return
0
;
}
/* Otherwise, read the chunk offset */
offset_offset
=
(
(
chunk
-
1
)
*
offset_len
);
file
->
read
(
file
,
&
u
,
(
resource
->
offset
+
offset_offset
),
offset_len
);
*
offset
=
(
chunks_len
+
(
(
offset_len
==
sizeof
(
u
.
offset_64
)
)
?
u
.
offset_64
:
u
.
offset_32
)
);
if
(
*
offset
>
zlen
)
{
DBG
(
"Chunk %d offset lies outside resource
\n
"
,
chunk
);
return
-
1
;
}
return
0
;
}
/**
* Read chunk from a compressed resource
*
* @v file Virtual file
* @v header WIM header
* @v resource Resource
* @v chunk Chunk number
* @v buf Chunk buffer
* @ret rc Return status code
*/
static
int
wim_chunk
(
struct
vdisk_file
*
file
,
struct
wim_header
*
header
,
struct
wim_resource_header
*
resource
,
unsigned
int
chunk
,
struct
wim_chunk_buffer
*
buf
)
{
ssize_t
(
*
decompress
)
(
const
void
*
data
,
size_t
len
,
void
*
buf
);
unsigned
int
chunks
;
size_t
offset
;
size_t
next_offset
;
size_t
len
;
size_t
expected_out_len
;
ssize_t
out_len
;
int
rc
;
/* Get chunk compressed data offset and length */
if
(
(
rc
=
wim_chunk_offset
(
file
,
resource
,
chunk
,
&
offset
)
)
!=
0
)
return
rc
;
if
(
(
rc
=
wim_chunk_offset
(
file
,
resource
,
(
chunk
+
1
),
&
next_offset
)
)
!=
0
)
return
rc
;
len
=
(
next_offset
-
offset
);
/* Calculate uncompressed length */
assert
(
resource
->
len
>
0
);
chunks
=
(
(
resource
->
len
+
WIM_CHUNK_LEN
-
1
)
/
WIM_CHUNK_LEN
);
expected_out_len
=
WIM_CHUNK_LEN
;
if
(
chunk
>=
(
chunks
-
1
)
)
expected_out_len
-=
(
-
resource
->
len
&
(
WIM_CHUNK_LEN
-
1
)
);
/* Read possibly-compressed data */
if
(
len
==
expected_out_len
)
{
/* Chunk did not compress; read raw data */
file
->
read
(
file
,
buf
->
data
,
(
resource
->
offset
+
offset
),
len
);
}
else
{
uint8_t
zbuf
[
len
];
/* Read compressed data into a temporary buffer */
file
->
read
(
file
,
zbuf
,
(
resource
->
offset
+
offset
),
len
);
/* Identify decompressor */
if
(
header
->
flags
&
WIM_HDR_LZX
)
{
decompress
=
lzx_decompress
;
}
else
{
DBG
(
"Can't handle unknown compression scheme %#08x "
"for %#llx chunk %d at [%#llx+%#llx)
\n
"
,
header
->
flags
,
resource
->
offset
,
chunk
,
(
resource
->
offset
+
offset
),
(
resource
->
offset
+
offset
+
len
)
);
return
-
1
;
}
/* Decompress data */
out_len
=
decompress
(
zbuf
,
len
,
NULL
);
if
(
out_len
<
0
)
return
out_len
;
if
(
(
(
size_t
)
out_len
)
!=
expected_out_len
)
{
DBG
(
"Unexpected output length %#lx (expected %#zx)
\n
"
,
out_len
,
expected_out_len
);
return
-
1
;
}
decompress
(
zbuf
,
len
,
buf
->
data
);
}
return
0
;
}
/**
* Read from a (possibly compressed) resource
*
* @v file Virtual file
* @v header WIM header
* @v resource Resource
* @v data Data buffer
* @v offset Starting offset
* @v len Length
* @ret rc Return status code
*/
int
wim_read
(
struct
vdisk_file
*
file
,
struct
wim_header
*
header
,
struct
wim_resource_header
*
resource
,
void
*
data
,
size_t
offset
,
size_t
len
)
{
static
struct
vdisk_file
*
cached_file
;
static
size_t
cached_resource_offset
;
static
unsigned
int
cached_chunk
;
size_t
zlen
=
(
resource
->
zlen__flags
&
WIM_RESHDR_ZLEN_MASK
);
unsigned
int
chunk
;
size_t
skip_len
;
size_t
frag_len
;
int
rc
;
/* Sanity checks */
if
(
(
offset
+
len
)
>
resource
->
len
)
{
DBG
(
"Resource too short (%#llx bytes)
\n
"
,
resource
->
len
);
return
-
1
;
}
if
(
(
resource
->
offset
+
zlen
)
>
file
->
len
)
{
DBG
(
"Resource exceeds length of file
\n
"
);
return
-
1
;
}
/* If resource is uncompressed, just read the raw data */
if
(
!
(
resource
->
zlen__flags
&
(
WIM_RESHDR_COMPRESSED
|
WIM_RESHDR_PACKED_STREAMS
)
)
)
{
file
->
read
(
file
,
data
,
(
resource
->
offset
+
offset
),
len
);
return
0
;
}
/* Read from each chunk overlapping the target region */
while
(
len
)
{
/* Calculate chunk number */
chunk
=
(
offset
/
WIM_CHUNK_LEN
);
/* Read chunk, if not already cached */
if
(
(
file
!=
cached_file
)
||
(
resource
->
offset
!=
cached_resource_offset
)
||
(
chunk
!=
cached_chunk
)
)
{
/* Read chunk */
if
(
(
rc
=
wim_chunk
(
file
,
header
,
resource
,
chunk
,
&
wim_chunk_buffer
)
)
!=
0
)
return
rc
;
/* Update cache */
cached_file
=
file
;
cached_resource_offset
=
resource
->
offset
;
cached_chunk
=
chunk
;
}
/* Copy fragment from this chunk */
skip_len
=
(
offset
%
WIM_CHUNK_LEN
);
frag_len
=
(
WIM_CHUNK_LEN
-
skip_len
);
if
(
frag_len
>
len
)
frag_len
=
len
;
memcpy
(
data
,
(
wim_chunk_buffer
.
data
+
skip_len
),
frag_len
);
/* Move to next chunk */
data
+=
frag_len
;
offset
+=
frag_len
;
len
-=
frag_len
;
}
return
0
;
}
/**
* Get number of images
*
* @v file Virtual file
* @v header WIM header
* @v count Count of images to fill in
* @ret rc Return status code
*/
int
wim_count
(
struct
vdisk_file
*
file
,
struct
wim_header
*
header
,
unsigned
int
*
count
)
{
struct
wim_lookup_entry
entry
;
size_t
offset
;
int
rc
;
/* Count metadata entries */
for
(
offset
=
0
;
(
offset
+
sizeof
(
entry
)
)
<=
header
->
lookup
.
len
;
offset
+=
sizeof
(
entry
)
)
{
/* Read entry */
if
(
(
rc
=
wim_read
(
file
,
header
,
&
header
->
lookup
,
&
entry
,
offset
,
sizeof
(
entry
)
)
)
!=
0
)
return
rc
;
/* Check for metadata entries */
if
(
entry
.
resource
.
zlen__flags
&
WIM_RESHDR_METADATA
)
{
(
*
count
)
++
;
DBG2
(
"...found image %d metadata at +%#zx
\n
"
,
*
count
,
offset
);
}
}
return
0
;
}
/**
* Get WIM image metadata
*
* @v file Virtual file
* @v header WIM header
* @v index Image index, or 0 to use boot image
* @v meta Metadata to fill in
* @ret rc Return status code
*/
int
wim_metadata
(
struct
vdisk_file
*
file
,
struct
wim_header
*
header
,
unsigned
int
index
,
struct
wim_resource_header
*
meta
)
{
struct
wim_lookup_entry
entry
;
size_t
offset
;
unsigned
int
found
=
0
;
int
rc
;
/* If no image index is specified, just use the boot metadata */
if
(
index
==
0
)
{
memcpy
(
meta
,
&
header
->
boot
,
sizeof
(
*
meta
)
);
return
0
;
}
/* Look for metadata entry */
for
(
offset
=
0
;
(
offset
+
sizeof
(
entry
)
)
<=
header
->
lookup
.
len
;
offset
+=
sizeof
(
entry
)
)
{
/* Read entry */
if
(
(
rc
=
wim_read
(
file
,
header
,
&
header
->
lookup
,
&
entry
,
offset
,
sizeof
(
entry
)
)
)
!=
0
)
return
rc
;
/* Look for our target entry */
if
(
entry
.
resource
.
zlen__flags
&
WIM_RESHDR_METADATA
)
{
found
++
;
DBG2
(
"...found image %d metadata at +%#zx
\n
"
,
found
,
offset
);
if
(
found
==
index
)
{
memcpy
(
meta
,
&
entry
.
resource
,
sizeof
(
*
meta
)
);
return
0
;
}
}
}
/* Fail if index was not found */
DBG
(
"Cannot find WIM image index %d in %s
\n
"
,
index
,
file
->
name
);
return
-
1
;
}
/**
* Get directory entry
*
* @v file Virtual file
* @v header WIM header
* @v meta Metadata
* @v name Name
* @v offset Directory offset (will be updated)
* @v direntry Directory entry to fill in
* @ret rc Return status code
*/
static
int
wim_direntry
(
struct
vdisk_file
*
file
,
struct
wim_header
*
header
,
struct
wim_resource_header
*
meta
,
const
wchar_t
*
name
,
size_t
*
offset
,
struct
wim_directory_entry
*
direntry
)
{
wchar_t
name_buf
[
wcslen
(
name
)
+
1
/* NUL */
];
int
rc
;
/* Search directory */
for
(
;
;
*
offset
+=
direntry
->
len
)
{
/* Read length field */
if
(
(
rc
=
wim_read
(
file
,
header
,
meta
,
direntry
,
*
offset
,
sizeof
(
direntry
->
len
)
)
)
!=
0
)
return
rc
;
/* Check for end of this directory */
if
(
!
direntry
->
len
)
{
DBG
(
"...directory entry
\"
%ls
\"
not found
\n
"
,
name
);
return
-
1
;
}
/* Read fixed-length portion of directory entry */
if
(
(
rc
=
wim_read
(
file
,
header
,
meta
,
direntry
,
*
offset
,
sizeof
(
*
direntry
)
)
)
!=
0
)
return
rc
;
/* Check name length */
if
(
direntry
->
name_len
>
sizeof
(
name_buf
)
)
continue
;
/* Read name */
if
(
(
rc
=
wim_read
(
file
,
header
,
meta
,
&
name_buf
,
(
*
offset
+
sizeof
(
*
direntry
)
),
sizeof
(
name_buf
)
)
)
!=
0
)
return
rc
;
/* Check name */
if
(
wcscasecmp
(
name
,
name_buf
)
!=
0
)
continue
;
DBG2
(
"...found entry
\"
%ls
\"\n
"
,
name
);
return
0
;
}
}
/**
* Get directory entry for a path
*
* @v file Virtual file
* @v header WIM header
* @v meta Metadata
* @v path Path to file/directory
* @v offset Directory entry offset to fill in
* @v direntry Directory entry to fill in
* @ret rc Return status code
*/
int
wim_path
(
struct
vdisk_file
*
file
,
struct
wim_header
*
header
,
struct
wim_resource_header
*
meta
,
const
wchar_t
*
path
,
size_t
*
offset
,
struct
wim_directory_entry
*
direntry
)
{
wchar_t
path_copy
[
wcslen
(
path
)
+
1
/* WNUL */
];
struct
wim_security_header
security
;
wchar_t
*
name
;
wchar_t
*
next
;
int
rc
;
/* Read security data header */
if
(
(
rc
=
wim_read
(
file
,
header
,
meta
,
&
security
,
0
,
sizeof
(
security
)
)
)
!=
0
)
return
rc
;
/* Get root directory offset */
direntry
->
subdir
=
(
(
security
.
len
+
sizeof
(
uint64_t
)
-
1
)
&
~
(
sizeof
(
uint64_t
)
-
1
)
);
/* Find directory entry */
name
=
memcpy
(
path_copy
,
path
,
sizeof
(
path_copy
)
);
do
{
next
=
wcschr
(
name
,
L'\\'
);
if
(
next
)
*
next
=
L'\0'
;
*
offset
=
direntry
->
subdir
;
if
(
(
rc
=
wim_direntry
(
file
,
header
,
meta
,
name
,
offset
,
direntry
)
)
!=
0
)
return
rc
;
name
=
(
next
+
1
);
}
while
(
next
);
return
0
;
}
/**
* Get file resource
*
* @v file Virtual file
* @v header WIM header
* @v meta Metadata
* @v path Path to file
* @v resource File resource to fill in
* @ret rc Return status code
*/
int
wim_file
(
struct
vdisk_file
*
file
,
struct
wim_header
*
header
,
struct
wim_resource_header
*
meta
,
const
wchar_t
*
path
,
struct
wim_resource_header
*
resource
)
{
struct
wim_directory_entry
direntry
;
struct
wim_lookup_entry
entry
;
size_t
offset
;
int
rc
;
/* Find directory entry */
if
(
(
rc
=
wim_path
(
file
,
header
,
meta
,
path
,
&
offset
,
&
direntry
)
)
!=
0
)
return
rc
;
/* File matching file entry */
for
(
offset
=
0
;
(
offset
+
sizeof
(
entry
)
)
<=
header
->
lookup
.
len
;
offset
+=
sizeof
(
entry
)
)
{
/* Read entry */
if
(
(
rc
=
wim_read
(
file
,
header
,
&
header
->
lookup
,
&
entry
,
offset
,
sizeof
(
entry
)
)
)
!=
0
)
return
rc
;
/* Look for our target entry */
if
(
memcmp
(
&
entry
.
hash
,
&
direntry
.
hash
,
sizeof
(
entry
.
hash
)
)
==
0
)
{
DBG
(
"...found file
\"
%ls
\"\n
"
,
path
);
memcpy
(
resource
,
&
entry
.
resource
,
sizeof
(
*
resource
)
);
return
0
;
}
}
DBG
(
"Cannot find file %ls
\n
"
,
path
);
return
-
1
;
}
/**
* Get length of a directory
*
* @v file Virtual file
* @v header WIM header
* @v meta Metadata
* @v offset Directory offset
* @v len Directory length to fill in (excluding terminator)
* @ret rc Return status code
*/
int
wim_dir_len
(
struct
vdisk_file
*
file
,
struct
wim_header
*
header
,
struct
wim_resource_header
*
meta
,
size_t
offset
,
size_t
*
len
)
{
struct
wim_directory_entry
direntry
;
int
rc
;
/* Search directory */
for
(
*
len
=
0
;
;
*
len
+=
direntry
.
len
)
{
/* Read length field */
if
(
(
rc
=
wim_read
(
file
,
header
,
meta
,
&
direntry
,
(
offset
+
*
len
),
sizeof
(
direntry
.
len
)
)
)
!=
0
)
return
rc
;
/* Check for end of this directory */
if
(
!
direntry
.
len
)
return
0
;
}
}
wimboot/wimboot-2.7.3/src/wim.h
0 → 100644
View file @
93996cf7
#ifndef _WIM_H
#define _WIM_H
/*
* Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
* @file
*
* WIM images
*
* The file format is documented in the document "Windows Imaging File
* Format (WIM)", available from
*
* http://www.microsoft.com/en-us/download/details.aspx?id=13096
*
* The wimlib source code is also a useful reference.
*
*/
#include <stdint.h>
/** A WIM resource header */
struct
wim_resource_header
{
/** Compressed length and flags */
uint64_t
zlen__flags
;
/** Offset */
uint64_t
offset
;
/** Uncompressed length */
uint64_t
len
;
}
__attribute__
((
packed
));
/** WIM resource header length mask */
#define WIM_RESHDR_ZLEN_MASK 0x00ffffffffffffffULL
/** WIM resource header flags */
enum
wim_resource_header_flags
{
/** Resource contains metadata */
WIM_RESHDR_METADATA
=
(
0x02ULL
<<
56
),
/** Resource is compressed */
WIM_RESHDR_COMPRESSED
=
(
0x04ULL
<<
56
),
/** Resource is compressed using packed streams */
WIM_RESHDR_PACKED_STREAMS
=
(
0x10ULL
<<
56
),
};
/** A WIM header */
struct
wim_header
{
/** Signature */
uint8_t
signature
[
8
];
/** Header length */
uint32_t
header_len
;
/** Verson */
uint32_t
version
;
/** Flags */
uint32_t
flags
;
/** Chunk length */
uint32_t
chunk_len
;
/** GUID */
uint8_t
guid
[
16
];
/** Part number */
uint16_t
part
;
/** Total number of parts */
uint16_t
parts
;
/** Number of images */
uint32_t
images
;
/** Lookup table */
struct
wim_resource_header
lookup
;
/** XML data */
struct
wim_resource_header
xml
;
/** Boot metadata */
struct
wim_resource_header
boot
;
/** Boot index */
uint32_t
boot_index
;
/** Integrity table */
struct
wim_resource_header
integrity
;
/** Reserved */
uint8_t
reserved
[
60
];
}
__attribute__
((
packed
));;
/** WIM header flags */
enum
wim_header_flags
{
/** WIM uses Xpress compresson */
WIM_HDR_XPRESS
=
0x00020000
,
/** WIM uses LZX compression */
WIM_HDR_LZX
=
0x00040000
,
};
/** A WIM file hash */
struct
wim_hash
{
/** SHA-1 hash */
uint8_t
sha1
[
20
];
}
__attribute__
((
packed
));
/** A WIM lookup table entry */
struct
wim_lookup_entry
{
/** Resource header */
struct
wim_resource_header
resource
;
/** Part number */
uint16_t
part
;
/** Reference count */
uint32_t
refcnt
;
/** Hash */
struct
wim_hash
hash
;
}
__attribute__
((
packed
));
/** WIM chunk length */
#define WIM_CHUNK_LEN 32768
/** A WIM chunk buffer */
struct
wim_chunk_buffer
{
/** Data */
uint8_t
data
[
WIM_CHUNK_LEN
];
};
/** Security data */
struct
wim_security_header
{
/** Length */
uint32_t
len
;
/** Number of entries */
uint32_t
count
;
}
__attribute__
((
packed
));
/** Directory entry */
struct
wim_directory_entry
{
/** Length */
uint64_t
len
;
/** Attributes */
uint32_t
attributes
;
/** Security ID */
uint32_t
security
;
/** Subdirectory offset */
uint64_t
subdir
;
/** Reserved */
uint8_t
reserved1
[
16
];
/** Creation time */
uint64_t
created
;
/** Last access time */
uint64_t
accessed
;
/** Last written time */
uint64_t
written
;
/** Hash */
struct
wim_hash
hash
;
/** Reserved */
uint8_t
reserved2
[
12
];
/** Streams */
uint16_t
streams
;
/** Short name length */
uint16_t
short_name_len
;
/** Name length */
uint16_t
name_len
;
}
__attribute__
((
packed
));
/** Normal file */
#define WIM_ATTR_NORMAL 0x00000080UL
/** No security information exists for this file */
#define WIM_NO_SECURITY 0xffffffffUL
/** Windows complains if the time fields are left at zero */
#define WIM_MAGIC_TIME 0x1a7b83d2ad93000ULL
extern
int
wim_header
(
struct
vdisk_file
*
file
,
struct
wim_header
*
header
);
extern
int
wim_count
(
struct
vdisk_file
*
file
,
struct
wim_header
*
header
,
unsigned
int
*
count
);
extern
int
wim_metadata
(
struct
vdisk_file
*
file
,
struct
wim_header
*
header
,
unsigned
int
index
,
struct
wim_resource_header
*
meta
);
extern
int
wim_read
(
struct
vdisk_file
*
file
,
struct
wim_header
*
header
,
struct
wim_resource_header
*
resource
,
void
*
data
,
size_t
offset
,
size_t
len
);
extern
int
wim_path
(
struct
vdisk_file
*
file
,
struct
wim_header
*
header
,
struct
wim_resource_header
*
meta
,
const
wchar_t
*
path
,
size_t
*
offset
,
struct
wim_directory_entry
*
direntry
);
extern
int
wim_file
(
struct
vdisk_file
*
file
,
struct
wim_header
*
header
,
struct
wim_resource_header
*
meta
,
const
wchar_t
*
path
,
struct
wim_resource_header
*
resource
);
extern
int
wim_dir_len
(
struct
vdisk_file
*
file
,
struct
wim_header
*
header
,
struct
wim_resource_header
*
meta
,
size_t
offset
,
size_t
*
len
);
#endif
/* _WIM_H */
wimboot/wimboot-2.7.3/src/wimboot.h
0 → 100644
View file @
93996cf7
#ifndef _WIMBOOT_H
#define _WIMBOOT_H
/*
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
* @file
*
* WIM boot loader
*
*/
/** Debug switch */
#ifndef DEBUG
#define DEBUG 1
#endif
/** Base segment address
*
* We place everything at 2000:0000, since this region is used by the
* Microsoft first-stage loaders (e.g. pxeboot.n12, etfsboot.com).
*/
#define BASE_SEG 0x2000
/** Base linear address */
#define BASE_ADDRESS ( BASE_SEG << 4 )
/** 64 bit long mode code segment */
#define LM_CS 0x10
/** 32 bit protected mode flat code segment */
#define FLAT_CS 0x20
/** 32 bit protected mode flat data segment */
#define FLAT_DS 0x30
/** 16 bit real mode code segment */
#define REAL_CS 0x50
/** 16 bit real mode data segment */
#define REAL_DS 0x60
#ifndef ASSEMBLY
#include <stdint.h>
#include <bootapp.h>
#include <cmdline.h>
/** Construct wide-character version of a string constant */
#define L( x ) _L ( x )
#define _L( x ) L ## x
/** Page size */
#define PAGE_SIZE 4096
/**
* Calculate start page number
*
* @v address Address
* @ret page Start page number
*/
static
inline
unsigned
int
page_start
(
const
void
*
address
)
{
return
(
(
(
intptr_t
)
address
)
/
PAGE_SIZE
);
}
/**
* Calculate end page number
*
* @v address Address
* @ret page End page number
*/
static
inline
unsigned
int
page_end
(
const
void
*
address
)
{
return
(
(
(
(
intptr_t
)
address
)
+
PAGE_SIZE
-
1
)
/
PAGE_SIZE
);
}
/**
* Calculate page length
*
* @v start Start address
* @v end End address
* @ret num_pages Number of pages
*/
static
inline
unsigned
int
page_len
(
const
void
*
start
,
const
void
*
end
)
{
return
(
page_end
(
end
)
-
page_start
(
start
)
);
}
/**
* Bochs magic breakpoint
*
*/
static
inline
void
bochsbp
(
void
)
{
__asm__
__volatile__
(
"xchgw %bx, %bx"
);
}
/** Debugging output */
#define DBG(...) do { \
if ( ( DEBUG & 1 ) && ( ! cmdline_quiet ) ) { \
printf ( __VA_ARGS__ ); \
} \
} while ( 0 )
/** Verbose debugging output */
#define DBG2(...) do { \
if ( ( DEBUG & 2 ) && ( ! cmdline_quiet ) ) { \
printf ( __VA_ARGS__ ); \
} \
} while ( 0 )
/* Branch prediction macros */
#define likely( x ) __builtin_expect ( !! (x), 1 )
#define unlikely( x ) __builtin_expect ( (x), 0 )
/* Mark parameter as unused */
#define __unused __attribute__ (( unused ))
#if __x86_64__
static
inline
void
call_real
(
struct
bootapp_callback_params
*
params
)
{
/* Not available in 64-bit mode */
(
void
)
params
;
}
static
inline
void
call_interrupt
(
struct
bootapp_callback_params
*
params
)
{
/* Not available in 64-bit mode */
(
void
)
params
;
}
static
inline
void
reboot
(
void
)
{
/* Not available in 64-bit mode */
}
#else
extern
void
call_real
(
struct
bootapp_callback_params
*
params
);
extern
void
call_interrupt
(
struct
bootapp_callback_params
*
params
);
extern
void
__attribute__
((
noreturn
))
reboot
(
void
);
#endif
extern
void
__attribute__
((
noreturn
,
format
(
printf
,
1
,
2
)
))
die
(
const
char
*
fmt
,
...
);
extern
unsigned
long
__stack_chk_guard
;
extern
void
init_cookie
(
void
);
#endif
/* ASSEMBLY */
#endif
/* _WIMBOOT_H */
wimboot/wimboot-2.7.3/src/wimfile.c
0 → 100644
View file @
93996cf7
/*
* Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
* @file
*
* WIM virtual files
*
*/
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <wchar.h>
#include "wimboot.h"
#include "vdisk.h"
#include "wim.h"
#include "wimfile.h"
/** A WIM virtual file */
struct
wim_file
{
/** Underlying virtual file */
struct
vdisk_file
*
file
;
/** WIM header */
struct
wim_header
header
;
/** Resource */
struct
wim_resource_header
resource
;
};
/** Maximum number of WIM virtual files */
#define WIM_MAX_FILES 8
/** WIM virtual files */
static
struct
wim_file
wim_files
[
WIM_MAX_FILES
];
/**
* Read from WIM virtual file
*
* @v file Virtual file
* @v data Data buffer
* @v offset Offset
* @v len Length
*/
static
void
wim_read_file
(
struct
vdisk_file
*
file
,
void
*
data
,
size_t
offset
,
size_t
len
)
{
struct
wim_file
*
wfile
=
file
->
opaque
;
int
rc
;
/* Read from resource */
if
(
(
rc
=
wim_read
(
wfile
->
file
,
&
wfile
->
header
,
&
wfile
->
resource
,
data
,
offset
,
len
)
)
!=
0
)
{
die
(
"Could not read from WIM virtual file
\n
"
);
}
}
/**
* Add WIM virtual file
*
* @v file Underlying virtual file
* @v index Image index, or 0 to use boot image
* @v path Path to file within WIM
* @v wname New virtual file name
* @ret file Virtual file, or NULL if not found
*/
struct
vdisk_file
*
wim_add_file
(
struct
vdisk_file
*
file
,
unsigned
int
index
,
const
wchar_t
*
path
,
const
wchar_t
*
wname
)
{
static
unsigned
int
wim_file_idx
=
0
;
struct
wim_resource_header
meta
;
struct
wim_file
*
wfile
;
char
name
[
VDISK_NAME_LEN
+
1
/* NUL */
];
unsigned
int
i
;
int
rc
;
/* Sanity check */
if
(
wim_file_idx
>=
WIM_MAX_FILES
)
die
(
"Too many WIM files
\n
"
);
wfile
=
&
wim_files
[
wim_file_idx
];
/* Construct ASCII file name */
snprintf
(
name
,
sizeof
(
name
),
"%ls"
,
wname
);
/* Skip files already added explicitly */
for
(
i
=
0
;
i
<
VDISK_MAX_FILES
;
i
++
)
{
if
(
strcasecmp
(
name
,
vdisk_files
[
i
].
name
)
==
0
)
return
NULL
;
}
/* Get WIM header */
if
(
(
rc
=
wim_header
(
file
,
&
wfile
->
header
)
)
!=
0
)
return
NULL
;
/* Get image metadata */
if
(
(
rc
=
wim_metadata
(
file
,
&
wfile
->
header
,
index
,
&
meta
)
)
!=
0
)
return
NULL
;
/* Get file resource */
if
(
(
rc
=
wim_file
(
file
,
&
wfile
->
header
,
&
meta
,
path
,
&
wfile
->
resource
)
)
!=
0
)
return
NULL
;
/* Add virtual file */
wim_file_idx
++
;
wfile
->
file
=
file
;
return
vdisk_add_file
(
name
,
wfile
,
wfile
->
resource
.
len
,
wim_read_file
);
}
/**
* Add WIM virtual files
*
* @v file Underlying virtual file
* @v index Image index, or 0 to use boot image
* @v paths List of paths to files within WIM
*/
void
wim_add_files
(
struct
vdisk_file
*
file
,
unsigned
int
index
,
const
wchar_t
**
paths
)
{
const
wchar_t
**
path
;
const
wchar_t
*
wname
;
const
wchar_t
*
tmp
;
/* Add any existent files within the list */
for
(
path
=
paths
;
*
path
;
path
++
)
{
/* Construct file name */
wname
=
*
path
;
for
(
tmp
=
wname
;
*
tmp
;
tmp
++
)
{
if
(
*
tmp
==
L'\\'
)
wname
=
(
tmp
+
1
);
}
/* Add virtual file, if existent */
wim_add_file
(
file
,
index
,
*
path
,
wname
);
}
}
wimboot/wimboot-2.7.3/src/wimfile.h
0 → 100644
View file @
93996cf7
#ifndef _WIMFILE_H
#define _WIMFILE_H
/*
* Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
* @file
*
* WIM virtual files
*
*/
#include <wchar.h>
struct
vdisk_file
;
extern
struct
vdisk_file
*
wim_add_file
(
struct
vdisk_file
*
file
,
unsigned
int
index
,
const
wchar_t
*
path
,
const
wchar_t
*
wname
);
extern
void
wim_add_files
(
struct
vdisk_file
*
file
,
unsigned
int
index
,
const
wchar_t
**
paths
);
#endif
/* _WIMFILE_H */
wimboot/wimboot-2.7.3/src/wimpatch.c
0 → 100644
View file @
93996cf7
/*
* Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
* @file
*
* WIM dynamic patching
*
*/
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <assert.h>
#include "wimboot.h"
#include "cmdline.h"
#include "vdisk.h"
#include "sha1.h"
#include "wim.h"
#include "wimpatch.h"
/** Directory into which files are injected */
#define WIM_INJECT_DIR "\\Windows\\System32"
struct
wim_patch
;
/** A region of a patched WIM file */
struct
wim_patch_region
{
/** Name */
const
char
*
name
;
/** Opaque token */
void
*
opaque
;
/** Starting offset of region */
size_t
offset
;
/** Length of region */
size_t
len
;
/** Patch region
*
* @v patch WIM patch
* @v region Patch region
* @v data Data buffer
* @v offset Relative offset
* @v len Length
* @ret rc Return status code
*/
int
(
*
patch
)
(
struct
wim_patch
*
patch
,
struct
wim_patch_region
*
region
,
void
*
data
,
size_t
offset
,
size_t
len
);
};
/** Regions of a patched WIM directory containing injected files */
struct
wim_patch_dir_regions
{
/** Subdirectory offset within parent entry */
struct
wim_patch_region
subdir
;
/** Copy of original directory entries */
struct
wim_patch_region
copy
;
/** Injected file directory entries */
struct
wim_patch_region
file
[
VDISK_MAX_FILES
];
}
__attribute__
((
packed
));
/** Regions of a patched WIM file */
union
wim_patch_regions
{
/** Structured list of regions */
struct
{
/** WIM header */
struct
wim_patch_region
header
;
/** Injected file contents */
struct
wim_patch_region
file
[
VDISK_MAX_FILES
];
/** Injected lookup table */
struct
{
/** Uncompressed copy of original lookup table */
struct
wim_patch_region
copy
;
/** Injected boot image metadata lookup table entry */
struct
wim_patch_region
boot
;
/** Injected file lookup table entries */
struct
wim_patch_region
file
[
VDISK_MAX_FILES
];
}
__attribute__
((
packed
))
lookup
;
/** Injected boot image metadata */
struct
{
/** Uncompressed copy of original metadata */
struct
wim_patch_region
copy
;
/** Patched directory containing injected files */
struct
wim_patch_dir_regions
dir
;
}
__attribute__
((
packed
))
boot
;
}
__attribute__
((
packed
));
/** Unstructured list of regions */
struct
wim_patch_region
region
[
0
];
};
/** An injected directory entry */
struct
wim_patch_dir_entry
{
/** Directory entry */
struct
wim_directory_entry
dir
;
/** Name */
wchar_t
name
[
VDISK_NAME_LEN
+
1
/* wNUL */
];
}
__attribute__
((
packed
));
/** A directory containing injected files */
struct
wim_patch_dir
{
/** Name */
const
char
*
name
;
/** Offset to parent directory entry */
size_t
parent
;
/** Offset to original directory entries */
size_t
offset
;
/** Length of original directory entries (excluding terminator) */
size_t
len
;
/** Offset to modified directory entries */
size_t
subdir
;
};
/** A patched WIM file */
struct
wim_patch
{
/** Virtual file */
struct
vdisk_file
*
file
;
/** Patched WIM header */
struct
wim_header
header
;
/** Original lookup table */
struct
wim_resource_header
lookup
;
/** Original boot image metadata */
struct
wim_resource_header
boot
;
/** Original boot index */
uint32_t
boot_index
;
/** Directory containing injected files */
struct
wim_patch_dir
dir
;
/** Patched regions */
union
wim_patch_regions
regions
;
};
/**
* Align WIM offset to nearest qword
*
* @v len Length
* @ret len Aligned length
*/
static
size_t
wim_align
(
size_t
len
)
{
return
(
(
len
+
0x07
)
&
~
0x07
);
}
/**
* Calculate WIM hash
*
* @v vfile Virtual file
* @v hash Hash to fill in
*/
static
void
wim_hash
(
struct
vdisk_file
*
vfile
,
struct
wim_hash
*
hash
)
{
uint8_t
ctx
[
SHA1_CTX_SIZE
];
uint8_t
buf
[
512
];
size_t
offset
;
size_t
len
;
/* Calculate SHA-1 digest */
sha1_init
(
ctx
);
for
(
offset
=
0
;
offset
<
vfile
->
len
;
offset
+=
len
)
{
/* Read block */
len
=
(
vfile
->
len
-
offset
);
if
(
len
>
sizeof
(
buf
)
)
len
=
sizeof
(
buf
);
vfile
->
read
(
vfile
,
buf
,
offset
,
len
);
/* Update digest */
sha1_update
(
ctx
,
buf
,
len
);
}
sha1_final
(
ctx
,
hash
->
sha1
);
}
/**
* Determine whether or not to inject file
*
* @v vfile Virtual file
* @ret inject Inject this file
*/
static
int
wim_inject_file
(
struct
vdisk_file
*
vfile
)
{
size_t
name_len
;
const
char
*
ext
;
/* Ignore non-existent files */
if
(
!
vfile
->
read
)
return
0
;
/* Ignore wimboot itself */
if
(
strcasecmp
(
vfile
->
name
,
"wimboot"
)
==
0
)
return
0
;
/* Ignore bootmgr files */
if
(
strcasecmp
(
vfile
->
name
,
"bootmgr"
)
==
0
)
return
0
;
if
(
strcasecmp
(
vfile
->
name
,
"bootmgr.exe"
)
==
0
)
return
0
;
/* Ignore BCD files */
if
(
strcasecmp
(
vfile
->
name
,
"BCD"
)
==
0
)
return
0
;
/* Locate file extension */
name_len
=
strlen
(
vfile
->
name
);
ext
=
(
(
name_len
>
4
)
?
(
vfile
->
name
+
name_len
-
4
)
:
""
);
/* Ignore .wim files */
if
(
strcasecmp
(
ext
,
".wim"
)
==
0
)
return
0
;
/* Ignore .sdi files */
if
(
strcasecmp
(
ext
,
".sdi"
)
==
0
)
return
0
;
/* Ignore .efi files */
if
(
strcasecmp
(
ext
,
".efi"
)
==
0
)
return
0
;
/* Ignore .ttf files */
if
(
strcasecmp
(
ext
,
".ttf"
)
==
0
)
return
0
;
return
1
;
}
/**
* Patch WIM header
*
* @v patch WIM patch
* @v region Patch region
* @v data Data buffer
* @v offset Relative offset
* @v len Length
* @ret rc Return status code
*/
static
int
wim_patch_header
(
struct
wim_patch
*
patch
,
struct
wim_patch_region
*
region
,
void
*
data
,
size_t
offset
,
size_t
len
)
{
struct
wim_header
*
header
=
&
patch
->
header
;
/* Sanity checks */
assert
(
offset
<
sizeof
(
*
header
)
);
assert
(
len
<=
(
sizeof
(
*
header
)
-
offset
)
);
/* Copy patched header */
if
(
patch
->
lookup
.
offset
!=
patch
->
header
.
lookup
.
offset
)
{
DBG2
(
"...patched WIM %s lookup table %#llx->%#llx
\n
"
,
region
->
name
,
patch
->
lookup
.
offset
,
patch
->
header
.
lookup
.
offset
);
}
if
(
patch
->
boot
.
offset
!=
patch
->
header
.
boot
.
offset
)
{
DBG2
(
"...patched WIM %s boot metadata %#llx->%#llx
\n
"
,
region
->
name
,
patch
->
boot
.
offset
,
patch
->
header
.
boot
.
offset
);
}
if
(
patch
->
boot_index
!=
patch
->
header
.
boot_index
)
{
DBG2
(
"...patched WIM %s boot index %d->%d
\n
"
,
region
->
name
,
patch
->
boot_index
,
patch
->
header
.
boot_index
);
}
memcpy
(
data
,
(
(
(
void
*
)
&
patch
->
header
)
+
offset
),
len
);
return
0
;
}
/**
* Patch injected file content
*
* @v patch WIM patch
* @v region Patch region
* @v data Data buffer
* @v offset Relative offset
* @v len Length
* @ret rc Return status code
*/
static
int
wim_patch_file
(
struct
wim_patch
*
patch
__unused
,
struct
wim_patch_region
*
region
,
void
*
data
,
size_t
offset
,
size_t
len
)
{
struct
vdisk_file
*
vfile
=
region
->
opaque
;
/* Read from file */
vfile
->
read
(
vfile
,
data
,
offset
,
len
);
return
0
;
}
/**
* Patch uncompressed copy of original lookup table
*
* @v patch WIM patch
* @v region Patch region
* @v data Data buffer
* @v offset Relative offset
* @v len Length
* @ret rc Return status code
*/
static
int
wim_patch_lookup_copy
(
struct
wim_patch
*
patch
,
struct
wim_patch_region
*
region
__unused
,
void
*
data
,
size_t
offset
,
size_t
len
)
{
int
rc
;
/* Read original lookup table */
if
(
(
rc
=
wim_read
(
patch
->
file
,
&
patch
->
header
,
&
patch
->
lookup
,
data
,
offset
,
len
)
)
!=
0
)
return
rc
;
return
0
;
}
/**
* Patch injected boot image metadata lookup table entry
*
* @v patch WIM patch
* @v region Patch region
* @v data Data buffer
* @v offset Relative offset
* @v len Length
* @ret rc Return status code
*/
static
int
wim_patch_lookup_boot
(
struct
wim_patch
*
patch
,
struct
wim_patch_region
*
region
__unused
,
void
*
data
,
size_t
offset
,
size_t
len
)
{
struct
wim_lookup_entry
entry
;
/* Sanity checks */
assert
(
offset
<
sizeof
(
entry
)
);
assert
(
len
<=
(
sizeof
(
entry
)
-
offset
)
);
/* Construct lookup table entry */
memset
(
&
entry
,
0
,
sizeof
(
entry
)
);
memcpy
(
&
entry
.
resource
,
&
patch
->
header
.
boot
,
sizeof
(
entry
.
resource
)
);
/* Copy lookup table entry */
memcpy
(
data
,
(
(
(
void
*
)
&
entry
)
+
offset
),
len
);
return
0
;
}
/**
* Patch injected file lookup table entry
*
* @v patch WIM patch
* @v region Patch region
* @v data Data buffer
* @v offset Relative offset
* @v len Length
* @ret rc Return status code
*/
static
int
wim_patch_lookup_file
(
struct
wim_patch
*
patch
__unused
,
struct
wim_patch_region
*
region
,
void
*
data
,
size_t
offset
,
size_t
len
)
{
struct
wim_patch_region
*
rfile
=
region
->
opaque
;
struct
vdisk_file
*
vfile
=
rfile
->
opaque
;
struct
wim_lookup_entry
entry
;
/* Sanity checks */
assert
(
offset
<
sizeof
(
entry
)
);
assert
(
len
<=
(
sizeof
(
entry
)
-
offset
)
);
/* Construct lookup table entry */
memset
(
&
entry
,
0
,
sizeof
(
entry
)
);
entry
.
resource
.
offset
=
rfile
->
offset
;
entry
.
resource
.
len
=
vfile
->
len
;
entry
.
resource
.
zlen__flags
=
entry
.
resource
.
len
;
entry
.
refcnt
=
1
;
wim_hash
(
vfile
,
&
entry
.
hash
);
/* Copy lookup table entry */
memcpy
(
data
,
(
(
(
void
*
)
&
entry
)
+
offset
),
len
);
DBG2
(
"...patched WIM %s %s
\n
"
,
region
->
name
,
vfile
->
name
);
return
0
;
}
/**
* Patch uncompressed copy of original boot metadata
*
* @v patch WIM patch
* @v region Patch region
* @v data Data buffer
* @v offset Relative offset
* @v len Length
* @ret rc Return status code
*/
static
int
wim_patch_boot_copy
(
struct
wim_patch
*
patch
,
struct
wim_patch_region
*
region
__unused
,
void
*
data
,
size_t
offset
,
size_t
len
)
{
int
rc
;
/* Read original boot metadata */
if
(
(
rc
=
wim_read
(
patch
->
file
,
&
patch
->
header
,
&
patch
->
boot
,
data
,
offset
,
len
)
)
!=
0
)
return
rc
;
return
0
;
}
/**
* Patch subdirectory offset within parent directory entry
*
* @v patch WIM patch
* @v region Patch region
* @v data Data buffer
* @v offset Relative offset
* @v len Length
* @ret rc Return status code
*/
static
int
wim_patch_dir_subdir
(
struct
wim_patch
*
patch
,
struct
wim_patch_region
*
region
,
void
*
data
,
size_t
offset
,
size_t
len
)
{
struct
wim_patch_dir
*
dir
=
region
->
opaque
;
uint64_t
subdir
=
dir
->
subdir
;
/* Sanity checks */
assert
(
offset
<
sizeof
(
subdir
)
);
assert
(
len
<=
(
sizeof
(
subdir
)
-
offset
)
);
/* Copy subdirectory offset */
memcpy
(
data
,
(
(
(
void
*
)
&
subdir
)
+
offset
),
len
);
DBG2
(
"...patched WIM %s %s %#llx
\n
"
,
region
->
name
,
dir
->
name
,
(
patch
->
header
.
boot
.
offset
+
subdir
)
);
return
0
;
}
/**
* Patch copy of original directory entries
*
* @v patch WIM patch
* @v region Patch region
* @v data Data buffer
* @v offset Relative offset
* @v len Length
* @ret rc Return status code
*/
static
int
wim_patch_dir_copy
(
struct
wim_patch
*
patch
,
struct
wim_patch_region
*
region
,
void
*
data
,
size_t
offset
,
size_t
len
)
{
struct
wim_patch_dir
*
dir
=
region
->
opaque
;
int
rc
;
/* Read portion of original boot metadata */
if
(
(
rc
=
wim_read
(
patch
->
file
,
&
patch
->
header
,
&
patch
->
boot
,
data
,
(
dir
->
offset
+
offset
),
len
)
)
!=
0
)
return
rc
;
return
0
;
}
/**
* Patch injected directory entries
*
* @v patch WIM patch
* @v region Patch region
* @v data Data buffer
* @v offset Relative offset
* @v len Length
* @ret rc Return status code
*/
static
int
wim_patch_dir_file
(
struct
wim_patch
*
patch
__unused
,
struct
wim_patch_region
*
region
,
void
*
data
,
size_t
offset
,
size_t
len
)
{
struct
wim_patch_region
*
rfile
=
region
->
opaque
;
struct
vdisk_file
*
vfile
=
rfile
->
opaque
;
struct
wim_patch_dir_entry
entry
;
size_t
name_len
=
strlen
(
vfile
->
name
);
unsigned
int
i
;
/* Sanity checks */
assert
(
offset
<
sizeof
(
entry
)
);
assert
(
len
<=
(
sizeof
(
entry
)
-
offset
)
);
/* Construct directory entry */
memset
(
&
entry
,
0
,
sizeof
(
entry
)
);
entry
.
dir
.
len
=
wim_align
(
sizeof
(
entry
)
);
entry
.
dir
.
attributes
=
WIM_ATTR_NORMAL
;
entry
.
dir
.
security
=
WIM_NO_SECURITY
;
entry
.
dir
.
created
=
WIM_MAGIC_TIME
;
entry
.
dir
.
accessed
=
WIM_MAGIC_TIME
;
entry
.
dir
.
written
=
WIM_MAGIC_TIME
;
wim_hash
(
vfile
,
&
entry
.
dir
.
hash
);
entry
.
dir
.
name_len
=
(
name_len
*
sizeof
(
entry
.
name
[
0
]
)
);
for
(
i
=
0
;
i
<
name_len
;
i
++
)
entry
.
name
[
i
]
=
vfile
->
name
[
i
];
/* Copy directory entry */
memcpy
(
data
,
(
(
(
void
*
)
&
entry
)
+
offset
),
len
);
DBG2
(
"...patched WIM %s %s
\n
"
,
region
->
name
,
vfile
->
name
);
return
0
;
}
/**
* Patch WIM region
*
* @v patch WIM patch
* @v region Patch region
* @v data Data buffer
* @v offset Relative offset
* @v len Length
* @ret rc Return status code
*/
static
int
wim_patch_region
(
struct
wim_patch
*
patch
,
struct
wim_patch_region
*
region
,
void
*
data
,
size_t
offset
,
size_t
len
)
{
size_t
skip
;
int
rc
;
/* Skip unused regions */
if
(
!
region
->
patch
)
return
0
;
/* Skip any data before this region */
skip
=
(
(
region
->
offset
>
offset
)
?
(
region
->
offset
-
offset
)
:
0
);
if
(
skip
>=
len
)
return
0
;
data
+=
skip
;
offset
+=
skip
;
len
-=
skip
;
/* Convert to relative offset within this region */
offset
-=
region
->
offset
;
/* Skip any data after this region */
if
(
offset
>=
region
->
len
)
return
0
;
if
(
len
>
(
region
->
len
-
offset
)
)
len
=
(
region
->
len
-
offset
);
/* Patch this region */
if
(
(
rc
=
region
->
patch
(
patch
,
region
,
data
,
offset
,
len
)
)
!=
0
)
return
rc
;
DBG2
(
"...patched WIM %s at [%#zx,%#zx)
\n
"
,
region
->
name
,
(
region
->
offset
+
offset
),
(
region
->
offset
+
offset
+
len
)
);
return
0
;
}
/**
* Construct patched WIM region
*
* @v region Patched region to fill in
* @v name Name
* @v opaque Opaque data
* @v offset Offset
* @v len Length
* @v patch Patch method
* @ret offset Next offset
*/
static
inline
__attribute__
((
always_inline
))
size_t
wim_construct_region
(
struct
wim_patch_region
*
region
,
const
char
*
name
,
void
*
opaque
,
size_t
offset
,
size_t
len
,
int
(
*
patch
)
(
struct
wim_patch
*
patch
,
struct
wim_patch_region
*
region
,
void
*
data
,
size_t
offset
,
size_t
len
)
)
{
DBG
(
"...patching WIM %s at [%#zx,%#zx)
\n
"
,
name
,
offset
,
(
offset
+
len
)
);
region
->
name
=
name
;
region
->
opaque
=
opaque
;
region
->
offset
=
offset
;
region
->
len
=
len
;
region
->
patch
=
patch
;
return
(
offset
+
len
);
}
/**
* Construct patch WIM directory regions
*
* @v patch WIM patch
* @v dir Patched directory
* @v offset Offset
* @v regions Patched directory regions to fill in
* @ret offset Next offset
*/
static
size_t
wim_construct_dir
(
struct
wim_patch
*
patch
,
struct
wim_patch_dir
*
dir
,
size_t
offset
,
struct
wim_patch_dir_regions
*
regions
)
{
struct
wim_patch_dir_entry
*
entry
;
struct
wim_patch_region
*
rfile
;
size_t
boot_offset
=
patch
->
header
.
boot
.
offset
;
unsigned
int
i
;
DBG
(
"...patching WIM directory at %#zx from [%#zx,%#zx)
\n
"
,
(
boot_offset
+
dir
->
parent
),
(
boot_offset
+
dir
->
offset
),
(
boot_offset
+
dir
->
offset
+
dir
->
len
)
);
/* Align directory entries */
offset
=
wim_align
(
offset
);
dir
->
subdir
=
(
offset
-
patch
->
header
.
boot
.
offset
);
/* Construct injected file directory entries */
for
(
i
=
0
;
i
<
VDISK_MAX_FILES
;
i
++
)
{
rfile
=
&
patch
->
regions
.
file
[
i
];
if
(
!
rfile
->
patch
)
continue
;
offset
=
wim_construct_region
(
&
regions
->
file
[
i
],
"dir.file"
,
rfile
,
offset
,
sizeof
(
*
entry
),
wim_patch_dir_file
);
offset
=
wim_align
(
offset
);
}
/* Construct copy of original directory entries */
offset
=
wim_construct_region
(
&
regions
->
copy
,
dir
->
name
,
dir
,
offset
,
dir
->
len
,
wim_patch_dir_copy
);
/* Allow space for directory terminator */
offset
+=
sizeof
(
entry
->
dir
.
len
);
/* Construct subdirectory offset within parent directory entry */
wim_construct_region
(
&
regions
->
subdir
,
"dir.subdir"
,
dir
,
(
boot_offset
+
dir
->
parent
+
offsetof
(
typeof
(
entry
->
dir
),
subdir
)
),
sizeof
(
entry
->
dir
.
subdir
),
wim_patch_dir_subdir
);
return
offset
;
}
/**
* Construct WIM patch
*
* @v file Virtual file
* @v boot_index New boot index (or zero)
* @v inject Inject files into WIM
* @v patch Patch to fill in
* @ret rc Return status code
*/
static
int
wim_construct_patch
(
struct
vdisk_file
*
file
,
unsigned
int
boot_index
,
int
inject
,
struct
wim_patch
*
patch
)
{
union
wim_patch_regions
*
regions
=
&
patch
->
regions
;
struct
wim_patch_region
*
rfile
;
struct
wim_resource_header
*
lookup
;
struct
wim_resource_header
*
boot
;
struct
wim_directory_entry
direntry
;
struct
wim_lookup_entry
*
entry
;
struct
vdisk_file
*
vfile
;
size_t
offset
;
unsigned
int
injected
=
0
;
unsigned
int
i
;
int
rc
;
/* Initialise patch */
memset
(
patch
,
0
,
sizeof
(
*
patch
)
);
patch
->
file
=
file
;
DBG
(
"...patching WIM %s
\n
"
,
file
->
name
);
/* Reset file length */
file
->
xlen
=
file
->
len
;
offset
=
file
->
len
;
/* Read WIM header */
if
(
(
rc
=
wim_header
(
file
,
&
patch
->
header
)
)
!=
0
)
return
rc
;
lookup
=
&
patch
->
header
.
lookup
;
boot
=
&
patch
->
header
.
boot
;
/* Patch header within original image body */
wim_construct_region
(
&
regions
->
header
,
"header"
,
NULL
,
0
,
sizeof
(
patch
->
header
),
wim_patch_header
);
/* Record original lookup table */
memcpy
(
&
patch
->
lookup
,
lookup
,
sizeof
(
patch
->
lookup
)
);
/* Record original metadata for selected boot image (which may
* not be the originally selected boot image).
*/
if
(
(
rc
=
wim_metadata
(
file
,
&
patch
->
header
,
boot_index
,
&
patch
->
boot
)
)
!=
0
)
return
rc
;
/* Record original boot index */
patch
->
boot_index
=
patch
->
header
.
boot_index
;
/* Update boot index in patched header, if applicable */
if
(
boot_index
)
patch
->
header
.
boot_index
=
boot_index
;
/* Do nothing more if injection is disabled */
if
(
!
inject
)
return
0
;
/* Construct injected files */
for
(
i
=
0
;
i
<
VDISK_MAX_FILES
;
i
++
)
{
vfile
=
&
vdisk_files
[
i
];
if
(
!
wim_inject_file
(
vfile
)
)
continue
;
offset
=
wim_construct_region
(
&
regions
->
file
[
i
],
vfile
->
name
,
vfile
,
offset
,
vfile
->
len
,
wim_patch_file
);
injected
++
;
}
/* Do nothing more if no files are injected */
if
(
injected
==
0
)
return
0
;
/* Calculate boot index for injected image */
if
(
(
rc
=
wim_count
(
file
,
&
patch
->
header
,
&
boot_index
)
)
!=
0
)
return
rc
;
patch
->
header
.
images
=
(
boot_index
+
1
);
patch
->
header
.
boot_index
=
patch
->
header
.
images
;
/* Construct injected lookup table */
lookup
->
offset
=
offset
=
wim_align
(
offset
);
offset
=
wim_construct_region
(
&
regions
->
lookup
.
copy
,
"lookup.copy"
,
NULL
,
offset
,
patch
->
lookup
.
len
,
wim_patch_lookup_copy
);
offset
=
wim_construct_region
(
&
regions
->
lookup
.
boot
,
"lookup.boot"
,
NULL
,
offset
,
sizeof
(
*
entry
),
wim_patch_lookup_boot
);
for
(
i
=
0
;
i
<
VDISK_MAX_FILES
;
i
++
)
{
rfile
=
&
regions
->
file
[
i
];
if
(
!
rfile
->
patch
)
continue
;
offset
=
wim_construct_region
(
&
regions
->
lookup
.
file
[
i
],
"lookup.file"
,
rfile
,
offset
,
sizeof
(
*
entry
),
wim_patch_lookup_file
);
}
lookup
->
offset
=
regions
->
lookup
.
copy
.
offset
;
lookup
->
len
=
(
offset
-
lookup
->
offset
);
lookup
->
zlen__flags
=
lookup
->
len
;
/* Locate directory containing injected files */
patch
->
dir
.
name
=
WIM_INJECT_DIR
;
if
(
(
rc
=
wim_path
(
file
,
&
patch
->
header
,
&
patch
->
boot
,
L
(
WIM_INJECT_DIR
),
&
patch
->
dir
.
parent
,
&
direntry
)
)
!=
0
)
return
rc
;
patch
->
dir
.
offset
=
direntry
.
subdir
;
if
(
(
rc
=
wim_dir_len
(
file
,
&
patch
->
header
,
&
patch
->
boot
,
patch
->
dir
.
offset
,
&
patch
->
dir
.
len
)
)
!=
0
)
return
rc
;
/* Construct injected boot image metadata */
boot
->
offset
=
offset
=
wim_align
(
offset
);
offset
=
wim_construct_region
(
&
regions
->
boot
.
copy
,
"boot.copy"
,
NULL
,
offset
,
patch
->
boot
.
len
,
wim_patch_boot_copy
);
offset
=
wim_construct_dir
(
patch
,
&
patch
->
dir
,
offset
,
&
regions
->
boot
.
dir
);
boot
->
len
=
(
offset
-
boot
->
offset
);
boot
->
zlen__flags
=
(
boot
->
len
|
WIM_RESHDR_METADATA
);
/* Record patched length */
file
->
xlen
=
offset
;
DBG
(
"...patching WIM length %#zx->%#zx
\n
"
,
file
->
len
,
file
->
xlen
);
return
0
;
}
/**
* Patch WIM file
*
* @v file Virtual file
* @v data Data buffer
* @v offset Offset
* @v len Length
*/
void
patch_wim
(
struct
vdisk_file
*
file
,
void
*
data
,
size_t
offset
,
size_t
len
)
{
static
struct
wim_patch
cached_patch
;
struct
wim_patch
*
patch
=
&
cached_patch
;
struct
wim_patch_region
*
region
;
unsigned
int
boot_index
;
unsigned
int
i
;
int
inject
;
int
rc
;
/* Do nothing unless patching is required */
boot_index
=
cmdline_index
;
inject
=
(
!
cmdline_rawwim
);
if
(
(
boot_index
==
0
)
&&
(
!
inject
)
)
return
;
/* Update cached patch if required */
if
(
file
!=
patch
->
file
)
{
if
(
(
rc
=
wim_construct_patch
(
file
,
boot_index
,
inject
,
patch
)
)
!=
0
)
{
die
(
"Could not patch WIM %s
\n
"
,
file
->
name
);
}
}
patch
=
&
cached_patch
;
/* Patch regions */
for
(
i
=
0
;
i
<
(
sizeof
(
patch
->
regions
)
/
sizeof
(
patch
->
regions
.
region
[
0
]
)
)
;
i
++
)
{
region
=
&
patch
->
regions
.
region
[
i
];
if
(
(
rc
=
wim_patch_region
(
patch
,
region
,
data
,
offset
,
len
)
)
!=
0
)
{
die
(
"Could not patch WIM %s %s at [%#zx,%#zx)
\n
"
,
file
->
name
,
region
->
name
,
offset
,
(
offset
+
len
)
);
}
}
}
wimboot/wimboot-2.7.3/src/wimpatch.h
0 → 100644
View file @
93996cf7
#ifndef _WIMPATCH_H
#define _WIMPATCH_H
/*
* Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
* @file
*
* WIM dynamic patching
*
*/
#include <stdint.h>
struct
vdisk_file
;
extern
void
patch_wim
(
struct
vdisk_file
*
file
,
void
*
data
,
size_t
offset
,
size_t
len
);
#endif
/* _WIMPATCH_H */
wimboot/wimboot-2.7.3/src/x86_64.i
0 → 100644
View file @
93996cf7
.
code64
wimboot/wimboot-2.7.3/src/xca.c
0 → 100644
View file @
93996cf7
/*
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
* @file
*
* Xpress Compression Algorithm (MS-XCA) decompression
*
*/
#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include <stdio.h>
#include "wimboot.h"
#include "huffman.h"
#include "xca.h"
/**
* Decompress XCA-compressed data
*
* @v data Compressed data
* @v len Length of compressed data
* @v buf Decompression buffer, or NULL
* @ret out_len Length of decompressed data, or negative error
*/
ssize_t
xca_decompress
(
const
void
*
data
,
size_t
len
,
void
*
buf
)
{
const
void
*
src
=
data
;
const
void
*
end
=
(
src
+
len
);
uint8_t
*
out
=
buf
;
size_t
out_len
=
0
;
size_t
out_len_threshold
=
0
;
const
struct
xca_huf_len
*
lengths
;
struct
xca
xca
;
uint32_t
accum
=
0
;
int
extra_bits
=
0
;
unsigned
int
huf
;
struct
huffman_symbols
*
sym
;
unsigned
int
raw
;
unsigned
int
match_len
;
unsigned
int
match_offset_bits
;
unsigned
int
match_offset
;
const
uint8_t
*
copy
;
int
rc
;
/* Process data stream */
while
(
src
<
end
)
{
/* (Re)initialise decompressor if applicable */
if
(
out_len
>=
out_len_threshold
)
{
/* Construct symbol lengths */
lengths
=
src
;
src
+=
sizeof
(
*
lengths
);
if
(
src
>
end
)
{
DBG
(
"XCA too short to hold Huffman lengths "
"table at input offset %#zx
\n
"
,
(
src
-
data
)
);
return
-
1
;
}
for
(
raw
=
0
;
raw
<
XCA_CODES
;
raw
++
)
xca
.
lengths
[
raw
]
=
xca_huf_len
(
lengths
,
raw
);
/* Construct Huffman alphabet */
if
(
(
rc
=
huffman_alphabet
(
&
xca
.
alphabet
,
xca
.
lengths
,
XCA_CODES
)
)
!=
0
)
return
rc
;
/* Initialise state */
accum
=
XCA_GET16
(
src
);
accum
<<=
16
;
accum
|=
XCA_GET16
(
src
);
extra_bits
=
16
;
/* Determine next threshold */
out_len_threshold
=
(
out_len
+
XCA_BLOCK_SIZE
);
}
/* Determine symbol */
huf
=
(
accum
>>
(
32
-
HUFFMAN_BITS
)
);
sym
=
huffman_sym
(
&
xca
.
alphabet
,
huf
);
raw
=
huffman_raw
(
sym
,
huf
);
accum
<<=
huffman_len
(
sym
);
extra_bits
-=
huffman_len
(
sym
);
if
(
extra_bits
<
0
)
{
accum
|=
(
XCA_GET16
(
src
)
<<
(
-
extra_bits
)
);
extra_bits
+=
16
;
}
/* Process symbol */
if
(
raw
<
XCA_END_MARKER
)
{
/* Literal symbol - add to output stream */
if
(
buf
)
*
(
out
++
)
=
raw
;
out_len
++
;
}
else
if
(
(
raw
==
XCA_END_MARKER
)
&&
(
src
>=
(
end
-
1
)
)
)
{
/* End marker symbol */
return
out_len
;
}
else
{
/* LZ77 match symbol */
raw
-=
XCA_END_MARKER
;
match_offset_bits
=
(
raw
>>
4
);
match_len
=
(
raw
&
0x0f
);
if
(
match_len
==
0x0f
)
{
match_len
=
XCA_GET8
(
src
);
if
(
match_len
==
0xff
)
{
match_len
=
XCA_GET16
(
src
);
}
else
{
match_len
+=
0x0f
;
}
}
match_len
+=
3
;
if
(
match_offset_bits
)
{
match_offset
=
(
(
accum
>>
(
32
-
match_offset_bits
))
+
(
1
<<
match_offset_bits
)
);
}
else
{
match_offset
=
1
;
}
accum
<<=
match_offset_bits
;
extra_bits
-=
match_offset_bits
;
if
(
extra_bits
<
0
)
{
accum
|=
(
XCA_GET16
(
src
)
<<
(
-
extra_bits
)
);
extra_bits
+=
16
;
}
/* Copy data */
out_len
+=
match_len
;
if
(
buf
)
{
copy
=
(
out
-
match_offset
);
while
(
match_len
--
)
*
(
out
++
)
=
*
(
copy
++
);
}
}
}
DBG
(
"XCA input overrun at output length %#zx
\n
"
,
out_len
);
return
-
1
;
}
wimboot/wimboot-2.7.3/src/xca.h
0 → 100644
View file @
93996cf7
#ifndef _XCA_H
#define _XCA_H
/*
* Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
* @file
*
* Xpress Compression Algorithm (MS-XCA) decompression
*
*/
#include <stdint.h>
#include "huffman.h"
/** Number of XCA codes */
#define XCA_CODES 512
/** XCA decompressor */
struct
xca
{
/** Huffman alphabet */
struct
huffman_alphabet
alphabet
;
/** Raw symbols
*
* Must immediately follow the Huffman alphabet.
*/
huffman_raw_symbol_t
raw
[
XCA_CODES
];
/** Code lengths */
uint8_t
lengths
[
XCA_CODES
];
};
/** XCA symbol Huffman lengths table */
struct
xca_huf_len
{
/** Lengths of each symbol */
uint8_t
nibbles
[
XCA_CODES
/
2
];
}
__attribute__
((
packed
));
/**
* Extract Huffman-coded length of a raw symbol
*
* @v lengths Huffman lengths table
* @v symbol Raw symbol
* @ret len Huffman-coded length
*/
static
inline
unsigned
int
xca_huf_len
(
const
struct
xca_huf_len
*
lengths
,
unsigned
int
symbol
)
{
return
(
(
(
lengths
->
nibbles
[
symbol
/
2
]
)
>>
(
4
*
(
symbol
%
2
)
)
)
&
0x0f
);
}
/** Get word from source data stream */
#define XCA_GET16( src ) ( { \
const uint16_t *src16 = src; \
src += sizeof ( *src16 ); \
*src16; } )
/** Get byte from source data stream */
#define XCA_GET8( src ) ( { \
const uint8_t *src8 = src; \
src += sizeof ( *src8 ); \
*src8; } )
/** XCA source data stream end marker */
#define XCA_END_MARKER 256
/** XCA block size */
#define XCA_BLOCK_SIZE ( 64 * 1024 )
extern
ssize_t
xca_decompress
(
const
void
*
data
,
size_t
len
,
void
*
buf
);
#endif
/* _XCA_H */
Prev
1
2
3
4
5
6
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