Compare commits

...

53 Commits

Author SHA1 Message Date
Bella Zhang 026afa7e3d
[iso] add Circle Linux to the list of Red-Hat derivatives
* Closes #2414.
2024-02-09 17:04:40 +00:00
Pete Batard 172888ac32
[dos] fix a CodeQL warning and harmonize code 2024-02-09 17:00:42 +00:00
Pete Batard 15e3886499
[iso] enable persistence support for Linux Mint
* Mint users sure are lucky that one of them *lied their way through* pretending that
  persistence actually used to work with previous version of Mint, when it never did,
  because they got us going through a whole refactor of the partition creation process
  just so we could make Mint persistence work.
* Closes #2428.
* Also fix a Coverity warning.
2024-02-09 16:59:28 +00:00
Pete Batard 0f23c47184
[misc] refactor partition creation 2024-02-08 14:17:03 +00:00
Pete Batard 164d4b0ab0
[misc] update workflows to use upload-artifact@v4
* See actions/upload-artifact#483, actions/upload-artifact#472#issuecomment-1861571655
  and ultimately https://github.com/actions/upload-artifact/blob/main/merge/README.md.
2024-02-07 20:11:09 +00:00
Pete Batard 1be7eaf306
[net] fix Fido script not being able to be launched again on user cancel
* Also update workflows to latest setup-msbuild
* Closes #2419
2024-02-07 19:24:17 +00:00
Pete Batard ac9a3f42d8
[misc] fix revoked bootloaders message does not display when using MBR
* Also update version to rufus-next
2024-02-06 20:02:36 +00:00
Pete Batard c2b2624b62
[vhd] improve handing of user selected filename on save to VHD/FFU
* Use of '*.*' as pattern in file save dialog could lead to assert and crash, so
  we now try to derive the type of image to be saved from the file extension. We
  also did not properly handle user cancellation in the file save dialog.
* Also update iso9660/iso9660_fs.c to latest proposal of El Torito image handling.
* Also add a couple asserts in the hash table functions so that, if these ever get
  triggered we will pick them from Windows Store reports, and clean up code.
2024-02-03 18:39:44 +00:00
Pete Batard 018ed3414b
[iso] improve El Torito image handling
* Update to latest libcdio proposal and fix incorrect image size.
* Also remove unnecessary calls in packme.cmd.
2024-01-24 17:51:40 +00:00
Pete Batard f6fd520d2a
[appstore] prevent packaging of ALPHA or BETA versions
* Also add package version override
2024-01-18 14:24:53 +00:00
Pete Batard b63f9ae93c
Rufus 4.4 (Build 2103) 2024-01-17 14:11:50 +00:00
Pete Batard fff39c56e8
[misc] fix UEFI:NTFS partition not being added when needed in MBR mode
* Also add support for SD card readers identifying themselves as SDXC.
2024-01-17 14:10:46 +00:00
Pete Batard 710bfe7f4d
[iso] work around ISOs that use broken symbolic links for UEFI bootloaders
* Per linuxmint/linuxmint#622 some ISOs may have a /EFI/boot/bootx64.efi that
  is a symbolic to a nonexisting file.
* This is originally due to a Debian bug that was fixed in:
  5bff71fea2
* Work around this by trying to extract a working bootx64.efi from the El-Torito image.
* Also improve DumpFatDir() to not replace already existing files.
2024-01-16 17:27:37 +00:00
Pete Batard ae6732c07b
[iso] add basic El-Torito image parsing to libcdio
* Based on El-Torito specs found at https://pdos.csail.mit.edu/6.828/2014/readings/boot-cdrom.pdf.
* Follows 7-zip's virtual '[BOOT]/#...' naming conventions (though we don't check for the full name).
* Limited to 8 NoEmul images.
2024-01-16 17:21:32 +00:00
Fred 2cebf914fd
[fat] align start of data region to MB
* Closes #2387
2024-01-10 13:36:50 +00:00
Pete Batard 70e87482c1
[misc] add some more Windows edition names
* Closes #2380
* Also fix a typo in the Norwegian translation, with thanks to @Legendarion
* Closes #2397
2024-01-10 12:53:07 +00:00
Pete Batard ebe01cc7b6
[dev] filter out Microsoft Dev Drives
* Microsoft Dev Drives are VHDs consisting of a small MSR followed by a large (50 GB or more)
  ReFS partition. See https://learn.microsoft.com/en-us/windows/dev-drive/.
* Closes #2395.
2024-01-08 16:43:52 +00:00
Pete Batard 51569d9e13
[misc] silence Coverity warnings
* Also update copyright year and improve uprintf error handling
* Also bump GitHub Actions dependencies. Note that we do NOT want to update to
  upload-artifact v4 because it BREAKS the creation of artifacts from matrix.
  See: https://github.com/actions/upload-artifact#v4---whats-new
* Closes #2382
* Closes #2383
2024-01-08 14:34:57 +00:00
dependabot[bot] 965d82c425
bump dessant/lock-threads from 4 to 5 (#2359)
Bumps [dessant/lock-threads](https://github.com/dessant/lock-threads) from 4 to 5.
- [Release notes](https://github.com/dessant/lock-threads/releases)
- [Changelog](https://github.com/dessant/lock-threads/blob/main/CHANGELOG.md)
- [Commits](https://github.com/dessant/lock-threads/compare/v4...v5)

---
updated-dependencies:
- dependency-name: dessant/lock-threads
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-25 18:24:40 +00:00
johnloopi b6d14d46df
[loc] Fixed typo in Norwegian translation
* Closes #2351
2023-11-14 12:13:49 +00:00
Pete Batard 89c1f8a72c
[iso] add BIOS support for Artix Linux
* Unfortunately, the Artix maintainers decided *NOT* to include the fat
  GRUB module for UEFI, so this will only work for BIOS boot...
2023-11-09 18:06:06 +00:00
Pete Batard e0b5c6d96f
[misc] improve the code related to the commandline hogger deletion
* Also small additional code improvements
2023-11-09 17:39:38 +00:00
Pete Batard 58c56eb398
[vhd] fix a crash when saving .ffu images with release version
* Also update Rufus next to 4.4
2023-10-27 22:45:24 +02:00
Pete Batard 020e0b7c3a
Rufus 4.3 (Build 2090)
* Also fix a CodeQL warning in process.c
2023-10-19 10:31:19 +01:00
Pete Batard 8edb487ac9
[misc] update ChangeLog for 4.3 BETA
* Also minor code cleanups and improvements.
2023-10-12 19:46:10 +01:00
Pete Batard 1630e912d4
[iso] add exception for Mint's LMDE
* Mint have decided to make their installation rely on a working /live/ ➔ /casper/ symlink for LMDE
  thereby breaking the promise of File System Transposition that all Debian derivatives should have.
* Because of this, trying to use FAT32 with LMDE will fail, as reported in linuxmint/live-installer#152.
* Therefore, now that we can replicate symlinks on NTFS, we add an exception to always enforce the use
  of NTFS for LMDE.
2023-10-12 18:28:56 +01:00
Pete Batard e9d588a6e0
[iso] add symlink support for target file systems that support it
* For now that means only NTFS. And we only do that for ISO-9660/Rock Ridge images.
2023-10-12 17:32:20 +01:00
Pete Batard 0bd38abd4e
[syslinux] improve support for Syslinux based Slax ISOs
* For some weird reason appending the base directory to the root syslinux.cfg
  we create does not appear to work with Slax. So we now always patch ldlinux.sys
  to include the base directory.
* Also add an exception to move the /slax/boot/EFI directory to /EFI.
* It should be noted that, as of slax-64bit-slackware-15.0.3.iso, the Slax UEFI
  Syslinux bootloaders appear to be broken (since creating a media without using
  Rufus at all per the Slax documentation does *not* produce a USB drive that was
  bootable in UEFI mode on 2 of the machines I tried).
* Also clean up some iso.c code and fix some unreachable code in ntfssect.c.
* Closes #2336.
* Closes #2338.
2023-10-11 20:46:46 +01:00
Pete Batard 45a5f22d43
[process] move the search for conflicting process to a background thread
* Removes the annoyance of having to wait for the process search to complete before media creation can start.
* Also update the "Process Hacker" references to its new "System Informer" name.
2023-10-10 22:22:45 +01:00
Pete Batard 8859c59548
[iso] count Rock Ridge duplicated files into the total size to process
* Duplicated symlinked Rock Ridge files were not counted into the total size needed
  to process the image and as a result, progress could go over 100% when extracting
  data (e.g. debian-live-12.1.0-amd64-lxqt.iso).
* Fix this by adding the duplicated files twice in the total block size.
2023-09-23 17:07:55 +01:00
Pete Batard 1fc790295c
[efi] update UEFI:NTFS to latest
* Add Windows bootmgr detection to report a more explicit error on security issues.
2023-09-08 17:33:25 +01:00
Pete Batard 99bffe8364
[misc] add '.wic' to the list of default image extensions
* '.wic' are DD images used by the Yocto project.
* Why Yocto chose to use their own extension instead of using the de-facto '.img' is beyond me but hey...
* Also update GitHub Actions dependencies to latest.
* Closes #2319.
2023-09-08 17:14:09 +01:00
Pete Batard 98725a0d5f
[misc] fix improper processing of net related errors
* With thanks to @Wack0
* Also silence a Coverity warning
2023-09-08 16:58:41 +01:00
Pete Batard 94ecf74c5f
[misc] use FORMAT_MESSAGE_FROM_HMODULE where possible and drop our custom message tables 2023-09-04 11:41:35 +01:00
Pete Batard d5bf53054b
[misc] improve retrieval of core directories
* This *might* help with the issue reported in #2296.
2023-08-28 11:08:03 +01:00
Pete Batard 866aa22a8b
[iso] fix Debian 12 Live not using persistence in BIOS mode
* The Isolinux/Syslinux append line has been moved to /isolinux/live.cfg
  so make sure we patch that file when persistence is enabled.
2023-08-27 23:03:43 +01:00
Pete Batard 9c6b1ad977
[vhd] fix Rufus being unable to open .vhd images
* Due to a typo in vhd.c where the second safe_stricmp() should be against ".vhd" and not ".vhdx" again.
* Also enable the ignore boot marker bypass for VHD/VHDX/FFU and don't misreport those images as
  "compressed disk images".
* Closes #2309.
2023-08-20 13:12:38 +01:00
Pete Batard 5b6574d6f6
[misc] add S Mode detection to Windows version reporting
* With thanks to @Wack0
2023-08-18 17:38:12 +01:00
Pete Batard c5ad16fdeb
[wue] add an expert feature to restrict a Windows installation to S Mode
* This is placed behind an expert wall (Ctrl-Alt-E) on account that:
  - If you happen to boot a Windows To Go drive in S Mode on a computer, it may set any
    existing Windows installation there to S Mode as well, *even if their disk is offline!*
  - It can be *exceedingly* tricky to get out of S Mode, as the SkuPolicyRequired registry
    trick alone may not be enough (i.e. You can have very much a Windows install in S Mode
    *without* SkuPolicyRequired being set anywhere).
* Also set version to rufus-next and fix a ChangeLog typo.
2023-08-15 11:15:16 +01:00
Pete Batard 5084317dd7
Rufus 4.2 (Build 2074)
* Also update UEFI:NTFS's NTFS driver to v1.7
2023-07-26 12:54:49 +01:00
AJIOB b81b440a20
[uefi] fix search for bootloaders in FAT images that have an 'EFI' volume label
* Per https://en.wikipedia.org/wiki/Design_of_the_FAT_file_system#Directory_entry it
  is possible to have a FAT directory entry with a 'EFI' volume label alongside with
  a 'EFI' subdirectory.
* If that happens, then the current Syslinux libfat_searchdir() code may treat the
  'EFI' volume label as an empty subdirectory and say that there are no bootloaders,
  even if the 'EFI\Boot\Boot###.efi' binaries really do exist.
* Fix this by filtering out entries with the 'volume label' attribute (0x08).
* For good measure, also filter out entries with the 'device' attribute (0x40), as
  it is technically possible to create a 'EFI' device leading to the same issue.
* Closes #2288.
* Closes #2289.
2023-07-24 23:55:47 +01:00
Pete Batard 64e85ed09a
[uefi] don't revoke Windows 11 or post Windows 10 20H1 boot media yet
* As opposed to what we originally asserted, Microsoft did enact a blanket revocation
  in SkuSiPolicy.p7b for all post 1703 up to 2305 Windows UEFI bootloaders.
* As a result, unconditionally copying SkuSiPolicy.p7b will result in media as recent
  as Windows 11 22H2 (v1) being flagged as revoked, which we don't want to enforce as
  long as Microsoft themselves haven't entered the enforcing phase of their Black
  Lotus mitigation (currently planned for early 2024).
* Because of this, while we add some revocation detection for post 1703 bootloaders,
  we set it to only go as far as 20H1 for now, which means that all post 20H1 Windows
  10 media and all Windows 11 media will not yet be flagged by Rufus as revoked and
  will still boot in a Secure Boot environment due to lack of an SkuSiPolicy.p7b.
* Ultimately, per #2244 we may look for a BOOTMGRSECURITYVERSIONNUMBER resource to
  blanket revoke all post 1703 - pre 2305 Windows UEFI bootloaders.
* Also remove the now unused comdlg32 library from the linker.
2023-07-15 23:20:59 +02:00
Pete Batard 3329304e67
[grub] update DB for GRUB 2.12~rc1
* Also fix some Coverity warnings in stdlg.c.
2023-07-13 10:11:52 +02:00
Pete Batard 65b84ea99d
[loc] update French translation 2023-07-10 12:40:55 +02:00
Pete Batard 5191c68337
[ui] keep user preferred image type when saving drive to VHD
* Also fix a Coverity warning and use a better description for SELECT image types.
2023-07-10 11:34:50 +02:00
Pete Batard 5bbcba8534
[vhd] add write support for .vhdx and .ffu images
* Also move VHD mounting function calls from iso.c to vhd.c and remove unused VHD footer elements.
2023-07-06 19:47:26 +01:00
Pete Batard f411d526d6
[misc] attempt to fix DLL address resolver for ARM64
* SymLoadModuleEx() on the DLL fails (with ERROR_SUCCESS, sic) on ARM64, so we have to resort
  to loading the DLL in memory and look for the "RSDS" section to access the GUID and Age.
* Except that, once you sort that, you end up with SymEnumSymbols() producing two separate
  addresses for each symbol, on account that the Windows 11 ARM64 DLLs are actually an
  unholy union of X64 and ARM64 *in the same binary*, under an abomination that Microsoft
  calls ARM64X (See https://learn.microsoft.com/en-us/windows/arm/arm64x-pe for details).
* And, of course, Microsoft did not provide any means during PDB enumeration to tell which
  address is for which arch. Especially, the bloody pSymInfo->TypeIndex, that they could
  easily have used for this, is utterly pointless as it remains set to 0...
* This means that, even after all this effort, we're still nowhere close to have a solution
  that can make DLL address resolution work on Windows 11 ARM64.
2023-07-05 22:25:25 +01:00
Pete Batard 0363bfe503
[misc] add an address resolver for internal DLL function calls
* Not sure if we'll use this to hook into FfuCaptureImage()/FfuApplyImage()/FfuMountImage()
  directly. But at least, if we ever need it, it's there...
2023-07-05 18:36:58 +01:00
Pete Batard ef345bf106
[uefi] fix UEFI bootloader extraction when case doesn't match
* With ISO-9660 being case sensitive, we could end up in situations where trying to extract
  '/efi/boot/bootx64.efi' for revocation validation would fail if the file on the image was
  stored as '/EFI/boot/bootx64.efi' (e.g. Debian 12).
* Fox this by storing the exact UEFI bootloader path we detected during ISO scan, and using
  this path for file extraction.
* Also add a Cancel choice to the revocation dialog and harmonize whitespaces.
2023-07-04 18:05:30 +01:00
ИEØ_ΙΙØZ bb66dfc492
[loc] update Traditional Chinese translation
* Closes #2274.
2023-07-04 13:29:27 +01:00
Pete Batard 10dbfdd7e1
[core] make sure the main partition size is aligned to the cluster size
* Having NTFS partitions properly aligned to the cluster size can drastically
  improve the speed of capturing a disk to an FFU image, as, when the size
  is aligned, the FFU capture uses the actual NTFS allocation map to only read
  and capture the clusters that are actually in use, whereas, if no aligned,
  FFU capture falls back to a sector by sector copy that is both much slower
  and also includes unwanted leftover garbage.
* Also only enable FFU when we detect FFUProvider.dll as a system library.
2023-07-04 13:26:04 +01:00
Pete Batard 0b1c68635a
[vhd] add experimental save to Full Flash Update (FFU) image support
* Full Flash Update (FFU) image support was added to dism with Windows 10 1709
  and is an alternate way to save a virtual hard disk for restoration.
* While more modern than VHD/VHDX, FFU creation only works for drives with file
  systems that Windows natively recognizes (FAT, NTFS) and that look like Windows
  installation media, so you can forget about FFU'ing a Linux disk.
* The other *intentional* drawback that Microsoft added is that they don't want
  anybody but themselves being able to create and restore FFU images, so, even
  as they have nice FfuApplyImage()/FfuCaptureImage() calls in FfuProvider.dll
  they have decided not to make these public.
* This means that, since we don't have time to spend on figuring and direct
  hooking internal DLL calls for x86_32, x86_64, ARM and ARM64 (and worrying
  that Microsoft may ever so slightly change their DLL between revs to break
  our hooks), we just call on dism.exe behind the scenes to create the FFU.
2023-07-03 23:57:04 +01:00
Pete Batard f9370e002e
[iso] fix a crash when parsing Windows ISOs with MinGW x86_32
* MinGW32's delay loading functionality is not yet up to par with MSVC's and especially, for
  some libraries (wininet, virtdisk) attempting to delay load them simply crashes the runtime.
* This results in the MinGW32 version of the app crashing when selecting a Windows ISO, as we
  will then try to mount the ISO using virtdisk to poke the build version. Note that this crash
  does not happen with the MinGW64 version or with MSVC.
* Closes #2272.
* Also fix a Coverity warning in SaveImageThread() and improve the VHD saving code.
2023-07-02 13:15:51 +01:00
62 changed files with 2692 additions and 2122 deletions

View File

@ -40,15 +40,15 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
uses: github/codeql-action/init@v3
with:
languages: cpp
- name: Add MSBuild to PATH
uses: microsoft/setup-msbuild@v1
uses: microsoft/setup-msbuild@v2
with:
msbuild-architecture: x64
@ -56,4 +56,4 @@ jobs:
run: msbuild ${{env.SOLUTION_FILE_PATH}} /m /p:Configuration=${{ env.BUILD_CONFIGURATION}},Platform=${{ env.TARGET_PLATFORM }}
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
uses: github/codeql-action/analyze@v3

View File

@ -27,7 +27,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 0
submodules: recursive
@ -44,7 +44,7 @@ jobs:
run: echo "${{github.workspace}}/cov-analysis-win64/bin" >> $GITHUB_PATH
- name: Add MSBuild to PATH
uses: microsoft/setup-msbuild@v1
uses: microsoft/setup-msbuild@v2
- name: Build with Coverity
run: |

View File

@ -9,7 +9,7 @@ jobs:
lock:
runs-on: ubuntu-latest
steps:
- uses: dessant/lock-threads@v4
- uses: dessant/lock-threads@v5
with:
github-token: ${{ github.token }}
issue-inactive-days: '90'

View File

@ -53,7 +53,7 @@ jobs:
upx
- name: Checkout repository
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 0
submodules: recursive
@ -63,14 +63,18 @@ jobs:
shell: bash
if: ${{ !startsWith(github.ref, 'refs/tags/') }}
# This ONLY works if the shell is bash or if using $env:GITHUB_OUTPUT
run: echo "option=--enable-alpha" >> $GITHUB_OUTPUT
run: |
echo "option=--enable-alpha" >> $GITHUB_OUTPUT
sed -b -i 's/VALUE "InternalName", "Rufus"/VALUE "InternalName", "Rufus (ALPHA)"/' ./src/rufus.rc
- name: Set BETA
id: set_beta
shell: bash
if: ${{ startsWith(github.ref, 'refs/tags/') && contains(github.ref, 'BETA') }}
# This ONLY works if the shell is bash or if using $env:GITHUB_OUTPUT
run: echo "option=--enable-beta" >> $GITHUB_OUTPUT
run: |
echo "option=--enable-beta" >> $GITHUB_OUTPUT
sed -b -i 's/VALUE "InternalName", "Rufus"/VALUE "InternalName", "Rufus (BETA)"/' ./src/rufus.rc
- name: Build
run: |
@ -92,7 +96,18 @@ jobs:
- name: Upload artifacts
if: ${{ github.event_name == 'push' }}
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: MinGW
name: ${{ matrix.sys }}
path: ./*.exe
Extra-Step-To-Merge-Artifacts-Thanks-To-Upload-Artifact-v4-Breaking-Backwards-Compatibility:
runs-on: windows-latest
needs: MinGW-Build
steps:
- name: Merge Artifacts
uses: actions/upload-artifact/merge@v4
if: ${{ github.event_name == 'push' }}
with:
name: MinGW
delete-merged: true

View File

@ -39,13 +39,13 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 0
submodules: recursive
- name: Add MSBuild to PATH
uses: microsoft/setup-msbuild@v1
uses: microsoft/setup-msbuild@v2
with:
msbuild-architecture: x64
@ -54,14 +54,18 @@ jobs:
shell: bash
if: ${{ !startsWith(github.ref, 'refs/tags/') }}
# This ONLY works if the shell is bash or if using $env:GITHUB_OUTPUT
run: echo "option=/DALPHA" >> $GITHUB_OUTPUT
run: |
echo "option=/DALPHA" >> $GITHUB_OUTPUT
sed -b -i 's/VALUE "InternalName", "Rufus"/VALUE "InternalName", "Rufus (ALPHA)"/' ./src/rufus.rc
- name: Set BETA
id: set_beta
shell: bash
if: ${{ startsWith(github.ref, 'refs/tags/') && contains(github.ref, 'BETA') }}
# This ONLY works if the shell is bash or if using $env:GITHUB_OUTPUT
run: echo "option=/DBETA" >> $GITHUB_OUTPUT
run: |
echo "option=/DBETA" >> $GITHUB_OUTPUT
sed -b -i 's/VALUE "InternalName", "Rufus"/VALUE "InternalName", "Rufus (BETA)"/' ./src/rufus.rc
- name: Build
shell: cmd
@ -82,10 +86,21 @@ jobs:
curl --request POST --url https://www.virustotal.com/api/v3/monitor/items --header 'x-apikey: ${{ secrets.VIRUSTOTAL_API_KEY }}' --form path='/rufus_${{ matrix.TARGET_PLATFORM }}.exe' --form file=@./rufus_${{ matrix.TARGET_PLATFORM }}.exe
- name: Upload artifacts
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
if: ${{ github.event_name == 'push' }}
with:
name: VS2022
name: ${{ matrix.TARGET_PLATFORM }}
path: |
./*.exe
./*.pdb
Extra-Step-To-Merge-Artifacts-Thanks-To-Upload-Artifact-v4-Breaking-Backwards-Compatibility:
runs-on: windows-latest
needs: VS2022-Build
steps:
- name: Merge Artifacts
uses: actions/upload-artifact/merge@v4
if: ${{ github.event_name == 'push' }}
with:
name: VS2022
delete-merged: true

View File

@ -19,7 +19,7 @@ TARGET := $(word 1,$(subst -, ,$(TUPLE)))
DEF_SUFFIX := $(if $(TARGET:x86_64=),.def,.def64)
.PHONY: all
all: dwmapi-delaylib.lib virtdisk-delaylib.lib wintrust-delaylib.lib
all: dwmapi-delaylib.lib version-delaylib.lib wintrust-delaylib.lib
%.def64: %.def
$(AM_V_SED) "s/@.*//" $< >$@

View File

@ -367,7 +367,7 @@ uninstall-am:
.PHONY: all
all: dwmapi-delaylib.lib virtdisk-delaylib.lib wintrust-delaylib.lib
all: dwmapi-delaylib.lib version-delaylib.lib wintrust-delaylib.lib
%.def64: %.def
$(AM_V_SED) "s/@.*//" $< >$@

4
.mingw/version.def Normal file
View File

@ -0,0 +1,4 @@
EXPORTS
GetFileVersionInfoSizeW@8
GetFileVersionInfoW@16
VerQueryValueA@16

View File

@ -1,7 +0,0 @@
EXPORTS
AttachVirtualDisk@24
GetVirtualDiskPhysicalPath@12
DetachVirtualDisk@12
OpenVirtualDisk@24
CreateVirtualDisk@36
GetVirtualDiskOperationProgress@12

View File

@ -133,12 +133,12 @@
<AdditionalOptions>/utf-8 $(ExternalCompilerOptions) %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<AdditionalDependencies>advapi32.lib;comctl32.lib;comdlg32.lib;crypt32.lib;gdi32.lib;ole32.lib;dwmapi.lib;setupapi.lib;shell32.lib;shlwapi.lib;wintrust.lib;virtdisk.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>advapi32.lib;comctl32.lib;crypt32.lib;gdi32.lib;ole32.lib;dwmapi.lib;setupapi.lib;shell32.lib;shlwapi.lib;version.lib;wintrust.lib;%(AdditionalDependencies)</AdditionalDependencies>
<UACExecutionLevel>RequireAdministrator</UACExecutionLevel>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
<TargetMachine>MachineX86</TargetMachine>
<DelayLoadDLLs>advapi32.dll;comctl32.dll;comdlg32.dll;crypt32.dll;gdi32.dll;ole32.dll;dwmapi.dll;setupapi.dll;shell32.dll;shlwapi.dll;wintrust.dll;virtdisk.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
<DelayLoadDLLs>advapi32.dll;comctl32.dll;crypt32.dll;gdi32.dll;ole32.dll;dwmapi.dll;setupapi.dll;shell32.dll;shlwapi.dll;version.dll;wintrust.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
</Link>
<ResourceCompile>
<PreprocessorDefinitions>_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
@ -162,12 +162,12 @@
<AdditionalOptions>/utf-8 $(ExternalCompilerOptions) %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<AdditionalDependencies>advapi32.lib;comctl32.lib;comdlg32.lib;crypt32.lib;gdi32.lib;ole32.lib;dwmapi.lib;setupapi.lib;shell32.lib;shlwapi.lib;wintrust.lib;virtdisk.lib;ole32.lib;advapi32.lib;gdi32.lib;shell32.lib;comdlg32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>advapi32.lib;comctl32.lib;crypt32.lib;gdi32.lib;ole32.lib;dwmapi.lib;setupapi.lib;shell32.lib;shlwapi.lib;version.lib;wintrust.lib;ole32.lib;advapi32.lib;gdi32.lib;shell32.lib;comdlg32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<UACExecutionLevel>RequireAdministrator</UACExecutionLevel>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
<AdditionalLibraryDirectories>C:\Program Files (x86)\Windows Kits\10\Lib\10.0.15063.0\um\arm</AdditionalLibraryDirectories>
<DelayLoadDLLs>advapi32.dll;comctl32.dll;comdlg32.dll;crypt32.dll;gdi32.dll;ole32.dll;dwmapi.dll;setupapi.dll;shell32.dll;shlwapi.dll;wintrust.dll;virtdisk.dll;ole32.dll;advapi32.dll;gdi32.dll;shell32.dll;comdlg32.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
<DelayLoadDLLs>advapi32.dll;comctl32.dll;crypt32.dll;gdi32.dll;ole32.dll;dwmapi.dll;setupapi.dll;shell32.dll;shlwapi.dll;version.dll;wintrust.dll;ole32.dll;advapi32.dll;gdi32.dll;shell32.dll;comdlg32.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
</Link>
<ResourceCompile>
<PreprocessorDefinitions>_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
@ -193,12 +193,12 @@
<AdditionalOptions>/utf-8 $(ExternalCompilerOptions) %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<AdditionalDependencies>advapi32.lib;comctl32.lib;comdlg32.lib;crypt32.lib;gdi32.lib;ole32.lib;dwmapi.lib;setupapi.lib;shell32.lib;shlwapi.lib;wintrust.lib;virtdisk.lib;ole32.lib;advapi32.lib;gdi32.lib;shell32.lib;comdlg32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>advapi32.lib;comctl32.lib;crypt32.lib;gdi32.lib;ole32.lib;dwmapi.lib;setupapi.lib;shell32.lib;shlwapi.lib;version.lib;wintrust.lib;ole32.lib;advapi32.lib;gdi32.lib;shell32.lib;comdlg32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<UACExecutionLevel>RequireAdministrator</UACExecutionLevel>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
<AdditionalLibraryDirectories>C:\Program Files (x86)\Windows Kits\10\Lib\10.0.16299.0\um\arm64</AdditionalLibraryDirectories>
<DelayLoadDLLs>advapi32.dll;comctl32.dll;comdlg32.dll;crypt32.dll;gdi32.dll;ole32.dll;dwmapi.dll;setupapi.dll;shell32.dll;shlwapi.dll;wintrust.dll;virtdisk.dll;ole32.dll;advapi32.dll;gdi32.dll;shell32.dll;comdlg32.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
<DelayLoadDLLs>advapi32.dll;comctl32.dll;crypt32.dll;gdi32.dll;ole32.dll;dwmapi.dll;setupapi.dll;shell32.dll;shlwapi.dll;version.dll;wintrust.dll;ole32.dll;advapi32.dll;gdi32.dll;shell32.dll;comdlg32.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
</Link>
<ResourceCompile>
<PreprocessorDefinitions>_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
@ -229,12 +229,12 @@
<AdditionalOptions>/utf-8 $(ExternalCompilerOptions) %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<AdditionalDependencies>advapi32.lib;comctl32.lib;comdlg32.lib;crypt32.lib;gdi32.lib;ole32.lib;dwmapi.lib;setupapi.lib;shell32.lib;shlwapi.lib;wintrust.lib;virtdisk.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>advapi32.lib;comctl32.lib;crypt32.lib;gdi32.lib;ole32.lib;dwmapi.lib;setupapi.lib;shell32.lib;shlwapi.lib;version.lib;wintrust.lib;%(AdditionalDependencies)</AdditionalDependencies>
<UACExecutionLevel>RequireAdministrator</UACExecutionLevel>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
<TargetMachine>MachineX64</TargetMachine>
<DelayLoadDLLs>advapi32.dll;comctl32.dll;comdlg32.dll;crypt32.dll;gdi32.dll;ole32.dll;dwmapi.dll;setupapi.dll;shell32.dll;shlwapi.dll;wintrust.dll;virtdisk.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
<DelayLoadDLLs>advapi32.dll;comctl32.dll;crypt32.dll;gdi32.dll;ole32.dll;dwmapi.dll;setupapi.dll;shell32.dll;shlwapi.dll;version.dll;wintrust.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
</Link>
<ResourceCompile>
<PreprocessorDefinitions>_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
@ -260,13 +260,13 @@
<StringPooling>true</StringPooling>
</ClCompile>
<Link>
<AdditionalDependencies>advapi32.lib;comctl32.lib;comdlg32.lib;crypt32.lib;gdi32.lib;ole32.lib;dwmapi.lib;setupapi.lib;shell32.lib;shlwapi.lib;wintrust.lib;virtdisk.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>advapi32.lib;comctl32.lib;crypt32.lib;gdi32.lib;ole32.lib;dwmapi.lib;setupapi.lib;shell32.lib;shlwapi.lib;version.lib;wintrust.lib;%(AdditionalDependencies)</AdditionalDependencies>
<UACExecutionLevel>RequireAdministrator</UACExecutionLevel>
<GenerateDebugInformation>false</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
<TargetMachine>MachineX86</TargetMachine>
<AdditionalOptions>/BREPRO %(AdditionalOptions)</AdditionalOptions>
<DelayLoadDLLs>advapi32.dll;comctl32.dll;comdlg32.dll;crypt32.dll;gdi32.dll;ole32.dll;dwmapi.dll;setupapi.dll;shell32.dll;shlwapi.dll;wintrust.dll;virtdisk.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
<DelayLoadDLLs>advapi32.dll;comctl32.dll;crypt32.dll;gdi32.dll;ole32.dll;dwmapi.dll;setupapi.dll;shell32.dll;shlwapi.dll;version.dll;wintrust.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
</Link>
<ResourceCompile>
<PreprocessorDefinitions>_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
@ -292,13 +292,13 @@
<StringPooling>true</StringPooling>
</ClCompile>
<Link>
<AdditionalDependencies>advapi32.lib;comctl32.lib;comdlg32.lib;crypt32.lib;gdi32.lib;ole32.lib;dwmapi.lib;setupapi.lib;shell32.lib;shlwapi.lib;wintrust.lib;virtdisk.lib;ole32.lib;advapi32.lib;gdi32.lib;shell32.lib;comdlg32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>advapi32.lib;comctl32.lib;crypt32.lib;gdi32.lib;ole32.lib;dwmapi.lib;setupapi.lib;shell32.lib;shlwapi.lib;version.lib;wintrust.lib;ole32.lib;advapi32.lib;gdi32.lib;shell32.lib;comdlg32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<UACExecutionLevel>RequireAdministrator</UACExecutionLevel>
<GenerateDebugInformation>false</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
<AdditionalLibraryDirectories>C:\Program Files (x86)\Windows Kits\10\Lib\10.0.15063.0\um\arm</AdditionalLibraryDirectories>
<AdditionalOptions>/BREPRO %(AdditionalOptions)</AdditionalOptions>
<DelayLoadDLLs>advapi32.dll;comctl32.dll;comdlg32.dll;crypt32.dll;gdi32.dll;ole32.dll;dwmapi.dll;setupapi.dll;shell32.dll;shlwapi.dll;wintrust.dll;virtdisk.dll;ole32.dll;advapi32.dll;gdi32.dll;shell32.dll;comdlg32.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
<DelayLoadDLLs>advapi32.dll;comctl32.dll;crypt32.dll;gdi32.dll;ole32.dll;dwmapi.dll;setupapi.dll;shell32.dll;shlwapi.dll;version.dll;wintrust.dll;ole32.dll;advapi32.dll;gdi32.dll;shell32.dll;comdlg32.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
</Link>
<ResourceCompile>
<PreprocessorDefinitions>_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
@ -326,13 +326,13 @@
<StringPooling>true</StringPooling>
</ClCompile>
<Link>
<AdditionalDependencies>advapi32.lib;comctl32.lib;comdlg32.lib;crypt32.lib;gdi32.lib;ole32.lib;dwmapi.lib;setupapi.lib;shell32.lib;shlwapi.lib;wintrust.lib;virtdisk.lib;ole32.lib;advapi32.lib;gdi32.lib;shell32.lib;comdlg32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>advapi32.lib;comctl32.lib;crypt32.lib;gdi32.lib;ole32.lib;dwmapi.lib;setupapi.lib;shell32.lib;shlwapi.lib;version.lib;wintrust.lib;ole32.lib;advapi32.lib;gdi32.lib;shell32.lib;comdlg32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<UACExecutionLevel>RequireAdministrator</UACExecutionLevel>
<GenerateDebugInformation>false</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
<AdditionalLibraryDirectories>C:\Program Files (x86)\Windows Kits\10\Lib\10.0.16299.0\um\arm64</AdditionalLibraryDirectories>
<AdditionalOptions>/BREPRO %(AdditionalOptions)</AdditionalOptions>
<DelayLoadDLLs>advapi32.dll;comctl32.dll;comdlg32.dll;crypt32.dll;gdi32.dll;ole32.dll;dwmapi.dll;setupapi.dll;shell32.dll;shlwapi.dll;wintrust.dll;virtdisk.dll;ole32.dll;advapi32.dll;gdi32.dll;shell32.dll;comdlg32.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
<DelayLoadDLLs>advapi32.dll;comctl32.dll;crypt32.dll;gdi32.dll;ole32.dll;dwmapi.dll;setupapi.dll;shell32.dll;shlwapi.dll;version.dll;wintrust.dll;ole32.dll;advapi32.dll;gdi32.dll;shell32.dll;comdlg32.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
</Link>
<ResourceCompile>
<PreprocessorDefinitions>_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
@ -363,13 +363,13 @@
<StringPooling>true</StringPooling>
</ClCompile>
<Link>
<AdditionalDependencies>advapi32.lib;comctl32.lib;comdlg32.lib;crypt32.lib;gdi32.lib;ole32.lib;dwmapi.lib;setupapi.lib;shell32.lib;shlwapi.lib;wintrust.lib;virtdisk.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>advapi32.lib;comctl32.lib;crypt32.lib;gdi32.lib;ole32.lib;dwmapi.lib;setupapi.lib;shell32.lib;shlwapi.lib;version.lib;wintrust.lib;%(AdditionalDependencies)</AdditionalDependencies>
<UACExecutionLevel>RequireAdministrator</UACExecutionLevel>
<GenerateDebugInformation>false</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
<TargetMachine>MachineX64</TargetMachine>
<AdditionalOptions>/BREPRO %(AdditionalOptions)</AdditionalOptions>
<DelayLoadDLLs>advapi32.dll;comctl32.dll;comdlg32.dll;crypt32.dll;gdi32.dll;ole32.dll;dwmapi.dll;setupapi.dll;shell32.dll;shlwapi.dll;wintrust.dll;virtdisk.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
<DelayLoadDLLs>advapi32.dll;comctl32.dll;crypt32.dll;gdi32.dll;ole32.dll;dwmapi.dll;setupapi.dll;shell32.dll;shlwapi.dll;version.dll;wintrust.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
</Link>
<ResourceCompile>
<PreprocessorDefinitions>_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>

View File

@ -1,3 +1,32 @@
o Version 4.4 (2024.01.17)
Add workaround for distros that use broken symbolic links as their UEFI bootloaders (such as Mint 21.3)
Add support for GRUB 2.12
Fix a crash when saving .ffu images
Fix UEFI:NTFS partition not being added, in MBR mode, for some Linux ISOs
Prevent Microsoft Dev Drives from being listed
Improve support for SDXC card readers
Improve Large FAT32 formatting by aligning start of data regions to 1 MB (courtesy of Fred)
o Version 4.3 (2023.10.19)
Add support for Rock Ridge symbolic links preservation when NTFS is used
Add an exception to enforce NTFS for Linux Mint's LMDE
Add an expert feature to restrict a Windows installation to S Mode
Fix persistence support for Debian 12 when booted in BIOS mode
Fix a regression that prevented the opening of .vhd images
Update UEFI:NTFS to report a more explicit error on bootmgr security issues
Improve the search for conflicting processes by running it in a background thread
Improve support for Slax Linux
o Version 4.2 (2023.07.26)
Add detection and warning for UEFI revoked bootloaders (including ones revoked through SkuSiPolicy.p7b)
Add ZIP64 support, to extract .zip images that are larger than 4 GB
Add saving and restoring current drive to/from compressed VHDX image
Add saving and restoring current drive to/from compressed FFU (Full Flash Update) image [EXPERIMENTAL]
Fix a crash when trying to open Windows ISOs, with the MinGW compiled x86 32-bit version
Fix an issue where ISOs that contain a boot image with an 'EFI' label are not detected as bootable
Increase the ISO → ESP limit for Debian 12 netinst images
Ensure that the main partition size is aligned to the cluster size
o Version 4.1 (2023.05.31)
Add timeouts on enumeration queries that may stall on some systems
Restore MS-DOS drive creation through the download of binaries from Microsoft

View File

@ -23,8 +23,8 @@ Features
* Create bootable drives from bootable disk images, including compressed ones
* Create Windows 11 installation drives for PCs that don't have TPM or Secure Boot
* Create [Windows To Go](https://en.wikipedia.org/wiki/Windows_To_Go) drives
* Create VHD/DD, VHDX and FFU images of an existing drive
* Create persistent Linux partitions
* Create VHD/DD images of a drive
* Compute MD5, SHA-1, SHA-256 and SHA-512 checksums of the selected image
* Improve Windows installation experience by automatically setting up OOBE parameters (local account, privacy options, etc.)
* Perform bad blocks checks, including detection of "fake" flash drives

View File

@ -1,2 +1,2 @@
@echo off
"C:\Program Files (x86)\Windows Kits\10\bin\10.0.22000.0\x64\signtool" sign /v /sha1 3dbc3a2a0e9ce8803b422cfdbc60acd33164965d /fd SHA256 /tr http://sha256timestamp.ws.symantec.com/sha256/timestamp /td SHA256 %1
"C:\Program Files (x86)\Windows Kits\10\bin\10.0.22000.0\x64\signtool" sign /v /sha1 3dbc3a2a0e9ce8803b422cfdbc60acd33164965d /fd SHA256 /tr http://sha256timestamp.ws.symantec.com/sha256/timestamp /td SHA256 %*

20
configure vendored
View File

@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.71 for rufus 4.2.
# Generated by GNU Autoconf 2.71 for rufus 4.5.
#
# Report bugs to <https://github.com/pbatard/rufus/issues>.
#
@ -611,8 +611,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='rufus'
PACKAGE_TARNAME='rufus'
PACKAGE_VERSION='4.2'
PACKAGE_STRING='rufus 4.2'
PACKAGE_VERSION='4.5'
PACKAGE_STRING='rufus 4.5'
PACKAGE_BUGREPORT='https://github.com/pbatard/rufus/issues'
PACKAGE_URL='https://rufus.ie'
@ -1269,7 +1269,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
\`configure' configures rufus 4.2 to adapt to many kinds of systems.
\`configure' configures rufus 4.5 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@ -1336,7 +1336,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
short | recursive ) echo "Configuration of rufus 4.2:";;
short | recursive ) echo "Configuration of rufus 4.5:";;
esac
cat <<\_ACEOF
@ -1428,7 +1428,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
rufus configure 4.2
rufus configure 4.5
generated by GNU Autoconf 2.71
Copyright (C) 2021 Free Software Foundation, Inc.
@ -1504,7 +1504,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
It was created by rufus $as_me 4.2, which was
It was created by rufus $as_me 4.5, which was
generated by GNU Autoconf 2.71. Invocation command line was
$ $0$ac_configure_args_raw
@ -2767,7 +2767,7 @@ fi
# Define the identity of the package.
PACKAGE='rufus'
VERSION='4.2'
VERSION='4.5'
printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h
@ -5309,7 +5309,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
This file was extended by rufus $as_me 4.2, which was
This file was extended by rufus $as_me 4.5, which was
generated by GNU Autoconf 2.71. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@ -5365,7 +5365,7 @@ ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config='$ac_cs_config_escaped'
ac_cs_version="\\
rufus config.status 4.2
rufus config.status 4.5
configured by $0, generated by GNU Autoconf 2.71,
with options \\"\$ac_cs_config\\"

View File

@ -1,4 +1,4 @@
AC_INIT([rufus], [4.2], [https://github.com/pbatard/rufus/issues], [rufus], [https://rufus.ie])
AC_INIT([rufus], [4.5], [https://github.com/pbatard/rufus/issues], [rufus], [https://rufus.ie])
AM_INIT_AUTOMAKE([-Wno-portability foreign no-dist no-dependencies])
AC_CONFIG_SRCDIR([src/rufus.c])
AC_CONFIG_MACRO_DIR([m4])

View File

@ -13,7 +13,7 @@
• 源代码: https://github.com/pbatard/rufus
• 更新日志: https://github.com/pbatard/rufus/blob/master/ChangeLog.txt","Rufus 是個能格式化並製作可開機 USB 快閃磁碟機USB 隨身碟、Memory Stick 等等)的工具。
• 官方網站: https://rufus.ie
• 源碼: https://github.com/pbatard/rufus
• 源碼: https://github.com/pbatard/rufus
• 更新日誌: https://github.com/pbatard/rufus/blob/master/ChangeLog.txt","Rufus je aplikacija koja olakšava formatiranje i stvaranje USB pokretačkih jedinica.
• Službena stranica: https://rufus.ie
• Šifra izvora: https://github.com/pbatard/rufus
@ -114,18 +114,20 @@
• Trang web chính thức: https://rufus.ie
• Mã nguồn: https://github.com/pbatard/rufus
• Nhật ký thay đổi: https://github.com/pbatard/rufus/blob/master/ChangeLog.txt"
"ReleaseNotes","3","Text","• Add timeouts on enumeration queries that may stall on some systems
• Restore MS-DOS drive creation through the download of binaries from Microsoft
• Update the log button icon
• Fix UEFI:NTFS incompatibility with Windows Dev Kit 2023 platform
• Fix more out of range pointer errors with Ubuntu/Fedora when booting in BIOS mode",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
"ReleaseNotes","3","Text","• Add workaround for distros that use broken symbolic links as their UEFI bootloaders (such as Mint 21.3)
• Add support for GRUB 2.12
• Fix a crash when saving .ffu images
• Fix UEFI:NTFS partition not being added, in MBR mode, for some Linux ISOs
• Prevent Microsoft Dev Drives from being listed
• Improve support for SDXC card readers
• Improve Large FAT32 formatting by aligning start of data regions to 1 MB (courtesy of Fred)",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
"Title","4","Text","Rufus",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
"ShortTitle","5","Text","",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
"SortTitle","6","Text","",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
"VoiceTitle","7","Text","",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
"ShortDescription","8","Text","","Rufus - The Reliable USB Formatting Utility","Rufus - أداة فرمتة الـ USB جديرة بالثقة","Rufus - Надеждната USB форматираща програма","Rufus - 可靠的 USB 格式化工具","Rufus - 快速可靠的 USB 格式化工具","Rufus - Pouzdan alat za formatiranje USB-a","Rufus - Spolehlivý program pro formátování USB","Rufus - Det pålidelige USB-formateringsværktøj","Rufus - de betrouwbare USB-formatteertool","Rufus - Luotettava USB-alustusohjelma","Rufus - L'utilitaire de formatage USB fiable","Rufus - Das zuverlässige USB-Formatierungstool","Rufus - Μία αξιόπιστη εφαρμογή διαμόρφωσης USB","Rufus - הכלי לאתחול USB האמין ביותר","Rufus - A megbízható USB-formázó segédprogram","Rufus - Utilitas Pemformatan USB yang Handal","Rufus - Utility affidabile per la formattazione di unità USB","Rufus - 信頼性の高い USB フォーマット ユーティリティ","Rufus - 신뢰할 수 있는 USB 포맷 유틸리티","Rufus - uzticama un vienkārša USB formatēšanas utilīta","Rufus - patikima USB formatavimo priemonė","Rufus - Utiliti pemformatan USB yang dipercayai","Rufus - Det pålitelige USB-formateringsprogrammet","Rufus، ابزاری کاربردی و قابل‌اطمینان برای فرمت کردن درایوهای USB","Rufus - niezawodne narzędzie do formatowania USB","Rufus - O Utilitário de Formatação USB Confiável","Rufus - O utilitário de confiança para formatação USB","Rufus - Instrumentul de încredere pentru formatări USB","Rufus - Надежная утилита для форматирования USB","Rufus - Pouzdan Alat Za Formatiranje USB diska","Rufus - Spoľahlivý program pre formátovanie USB","Rufus - zanesljivi pripomoček za USB formatiranje","Rufus, la herramienta de formateo de USBs en la que puedes confiar","Rufus - Det pålitliga verktyget för USB-formatering","Rufus - ยูทิลิตี้การฟอร์แมต USB ที่ไว้ใจได้","Rufus - Güvenilir USB Biçimlendirme Programı","Rufus - надійна утиліта для форматування USB-накопичувачів","Rufus - Tiện ích Định dạng USB Đáng tin cậy"
"DevStudio","9","Text","Pete Batard",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
"CopyrightTrademarkInformation","12","Text","© 2011-2023 Pete Batard",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
"CopyrightTrademarkInformation","12","Text","© 2011-2024 Pete Batard",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
"AdditionalLicenseTerms","13","Text","https://www.gnu.org/licenses/gpl-3.0.html","This application is licensed under the terms of the GNU Public License (GPL) version 3.
See https://www.gnu.org/licenses/gpl-3.0.en.html for details.","هذا التطبيق مُرخص بموجب شروط رخصة جنو (GNU) العمومية (GPL) الإصدار 3.
راجع https://www.gnu.org/licenses/gpl-3.0.ar.html لمزيد من التفاصيل.","Тази програма е лицензирана според условията на GNU Public License (GPL) версия 3.
@ -259,19 +261,19 @@ Xem tại https://www.gnu.org/licenses/gpl-3.0.html để biết thêm chi tiế
"OptionalPromo358x358","611","Relative path (or URL to file in Partner Center)","",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
"OptionalPromo1000x800","612","Relative path (or URL to file in Partner Center)","",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
"OptionalPromo414x180","613","Relative path (or URL to file in Partner Center)","",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
"Feature1","700","Text","","Format USB, flash card and virtual drives to FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3","تهيئة USB وبطاقة الفلاش ومحركات الأقراص الافتراضية إلى FAT / FAT32 / NTFS / UDF / exFAT / ReFS / ext2 / ext3","Форматиране на USB, карти памет и виртуални устройства с FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3","将 U 盘、存储卡或虚拟驱动器格式化为 FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3 格式","將 U 盤、存儲卡或虛擬驅動器格式化為 FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3 格式","Formatirajte USB, flash karticu i virtualne pogone na FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3","Formátování USB, flash karet a virtuálních jednotek na FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3","Formater USB, flash kort og virtuelle drev til FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3","USB, flashkaart en virtuele schijven formatteren naar FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3","Alusta USB-asemia, muistikortteja ja virtuaalisia asemia muotoon FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3","Formatez des périphériques USB, des cartes flash et des disques virtuels en FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3","Formatieren von USB, Flash-Karte und virtuellen Laufwerken in FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3","Μορφοποίηση USB, κάρτας flash και εικονικών μονάδων δίσκου σε FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3","אתחול USB, כרטיסי זיכרון וכוננים וירטואליים ל־FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3","USB, flash memóriakártyák és virtuális meghajtók formázása FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3 fájlrendszerre","Format USB, kartu flash dan penyimpanan maya ke FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3","Formatta USB, flash card e unità virtuali in FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3","USBメモリやSDカード、仮想ドライブをFAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3でフォーマットします。","USB, 플래시 카드 및 가상 드라이브를 FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3로 포맷","Formatē USB, atmiņas kartes un virtuālos diskus formātos FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3","Suformatuokite USB, flash kortelę ir virtualius diskus į FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3","Formatkan USB, kad flash dan pemacu maya kepada FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3","Formater USB, minnekort og virtuelle disker til FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3","فرمت USB، فلش کارت و درایوهای مجازی به FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3","Sformatuj nośnik używając: FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3","Formatar dispositivos USB, cartões flash e discos virtuais com FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3","Formatar dispositivos USB, cartão de memória e drives virtuais em FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3","Formatează USB, card flash si drive-uri virtuale la FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3","Форматировать USB, флешки и виртуальные диски в FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3","Formatiraj USB, flash kartice, i virtualne diskove u FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3","Naformátujte USB, kartu a virtuálne disky do FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3","FormatIRANJE USB, bliskavice in virtualnih pogonov na FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3","Formatee USB, tarjetas flash y unidades virtuales a FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3","Formatera USB-enheter, flash-kort och virtuella enheter till FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3","ฟอร์แมต USB, แฟลชการ์ด หรือไดร์ฟจำลองให้อยู่ในรูปแบบของ FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3","USB, flash kart ve sanal sürücüleri FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3 olarak biçimlendirin","Форматування USB-накопичувачів, флешок, карток пам'яті у FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3","Định dạng USB, thẻ nhớ hoặc ổ nhớ ảo với FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3"
"Feature2","701","Text","","Create FreeDOS bootable USB drives","إنشاء محركات أقراص USB قابلة للتشغيل من FreeDOS","Създаване на FreeDOS стартиращ USB устройства","创建 FreeDOS 可启动驱动器","創建 FreeDOS 可啟動驅動器","Stvaranje FreeDOS USB pogona za pokretanje","Vytvoření bootovacích disků USB se systémem FreeDOS","Lav FreeDOS opstartsbare USB drev","FreeDOS opstartbare USB-schijven aanmaken","Luo boottaavia FreeDOS USB-asemia","Créez des disques amorçable FreeDOS","FreeDOS-bootfähige USB-Laufwerke erstellen","Δημιουργήστε μονάδες USB με δυνατότητα εκκίνησης FreeDOS","יצירת כונני USB הניתנים לאתחול של FreeDOS","Bootolható FreeDOS USB meghajtó készítése","Buat perangkat USB FreeDOS yang dapat di boot","Crea unità USB avviabili FreeDOS","FreeDOSの起動可能ドライブを作成します。","FreeDOS 부팅 가능한 USB 드라이브 만들기","Izveido FreeDOS ielādes USB ierīces","Sukurkite FreeDOS įkrovos USB diskus","Buat pemacu USB boleh boot FreeDOS","Lag FreeDos oppstartbar USB stick","درایوهای USB قابل بوت FreeDOS را ایجاد کنید","Stwórz bootowalny nośnik USB FreeDOS","Criar discos USB inicializáveis FreeDOS","Criar unidades USB inicializáveis FreeDOS","Crează drive USB bootabil FreeDOS","Создать загрузочные USB-диски FreeDOS","Kreiraj FreeDOS butabilni USB disk","Vytvorte bootovacie usb zariadenia FreeDOS","Ustvarite FreeDOS zagonske USB pogone","Crear unidades USB de arranque FreeDOS","Skapa FreeDOS startbara USB-enheter","สร้าง USB ไดร์ฟที่บูตได้สำหรับระบบ FreeDOS","FreeDOS önyüklenebilir USB sürücüleri oluşturun","Створення завантажувальних пристроїв FreeDOS","Tạo USB có thể khởi động với FreeDOS"
"Feature3","702","Text","","Create bootable drives from bootable ISOs (Windows, Linux, etc.)","إنشاء محركات أقراص قابلة للتمهيد من ملفات ISO القابلة للتمهيد (Windows و Linux وما إلى ذلك)","Създаване на стартиращи устройства от ISO образи (Windows, Linux и др.)","从可启动 ISO 文件 (Windows 和 Linux 等) 创建可启动驱动器","從可啟動 ISO 文件 (Windows 和 Linux 等) 創建可啟動驅動器","Stvaranje pogona za pokretanje iz ISO-ova za pokretanje (Windows, Linux itd.)","Vytváření bootovacích jednotek ze zaváděcích ISO (Windows, Linux atd.)","Lav opstartsbarer drev fra opstartsbarer ISOer (Window, Linux, osv.)","Opstartbare schijven aanmaken via opstartbare ISO's (Windows, Linux, enz)","Luo käynnistysasemia boottaavista ISO-kuvista (Windows, Linux jne.)","Créez des disques amorçables à partir d'images ISOs (Windows, Linux, etc.)","Erstellen bootfähiger Laufwerke aus bootfähigen ISOs (Windows, Linux, etc.)","Δημιουργήστε εκκινήσιμες μονάδες από ISO με δυνατότητα εκκίνησης (Windows, Linux, κ.λπ.)","יצירת כוננים הניתנים לאתחול מקובצי ISO הניתנים לאתחול (Windows, Linux וכו')","Bootolható meghajtók készítése bootolható ISO képfájlokból (Windows, Linux, stb.)","Buat perangkat yang dapat di boot dari ISO (Windows, Linux, dll.)","Crea unità avviabili da ISO avviabili (Windows, Linux, ecc.)","WindowsやLinuxなどのISOファイルから起動可能ドライブを作成します。","부팅 가능한 ISO (Windows, Linux 등)에서 부팅 가능한 드라이브 만들기","Izveido ielādes ierīces no ISO failiem (Windows, Linux, u.c.)","Sukurkite įkrovos diskus iš įkrovos ISO (Windows, Linux ir kt.)","Buat pemacu boleh boot daripada ISO boleh boot (Windows, Linux, dll.)","Lag oppstartabar enhet/disk fra ISOer (Windows, Linux, etc.)","ایجاد درایوهای قابل بوت از ISOهای قابل بوت (ویندوز، لینوکس و غیره)","Twórz dyski rozruchowe z obrazów ISO (Windows, Linux itp.)","Criar discos inicializáveis a partir de ISOs inicializáveis (Windows, Linux, etc.)","Criar unidades inicializáveis a partir de ISOs inicializáveis (Windows, Linux, etc.)","Crează drive-uri bootabile de la ISO-uri bootabile (Windows, Linux, etc.)","Создать загрузочные диски из загрузочных ISO-образов (Windows, Linux и т.д.)","Kreirajte disk jedinice za pokretanje sistema od ISO-a koji se mogu pokretanja sistema (Windows, Linux itd.)","Vytvorte bootovacie jednotky z ISO súborov (Windows, Linux atď.)","Ustvarite zagonske pogone iz zagonskih ISO-jev (Windows, Linux itd.)","Cree unidades de arranque desde ISO de arranque (Windows, Linux, etc.)","Skapa startbara enheter från startbara ISO-filer (Windows, Linux, etc.)","สร้าง USB ไดร์ฟที่บูตได้จากไฟล์อิมเมจที่บูตได้ (เช่น ไฟล์ติดตั้ง Windows หรือ Linux เป็นต้น)","Önyüklenebilir ISO'lardan önyüklenebilir sürücüler oluşturun (Windows, Linux, vb.)","Створення завантажувальних пристроїв з завантажувальних образів (Windows, Linux, тощо)","Tạo ổ đĩa có thể khởi động từ các file ISO có thể khởi động (Windows, Linux, v.v...)"
"Feature4","703","Text","","Create bootable drives from bootable disk images, including compressed ones","إنشاء محركات أقراص قابلة للتمهيد من صور الأقراص القابلة للتمهيد ، بما في ذلك الأقراص المضغوطة","Създаване на стартиращи устройства от образи, включително компресирани такива","从可启动硬盘镜像 (包括压缩镜像) 创建可启动驱动器","從可啟動硬盤鏡像 (包括壓縮鏡像) 創建可啟動驅動器","Stvaranje pogona za pokretanje iz slika diska za pokretanje, uključujući komprimirane","Vytváření zaváděcích jednotek ze zaváděcích obrazů disků, včetně komprimovaných","Lav opstartsbarer drev fra opstartsbarer disk billeder, inklusiv komprimerede billeder","Opstartbare schijven aanmaken van opstartbare schijf-images, inclusief gecomprimeerde images","Luo käynnistysasemia boottaavista levykuvista, pakatut kuvat mukaanlukien","Créez des disques amorçables à partir d'images disque, y compris à partir d'images compressées","Erstellen bootfähiger Laufwerke aus bootfähigen Festplatten-Images, einschließlich komprimierter Images","Δημιουργήστε μονάδες εκκίνησης από εικόνες δίσκου με δυνατότητα εκκίνησης, συμπεριλαμβανομένων συμπιεσμένων","יצירת כוננים הניתנים לאתחול מקובצי תמונת דיסק הניתנים לאתחול, כולל קבצים דחוסים","Bootolható meghajtók készítése bootolható lemez képfájlokból, beleértve a tömörítetteket is","Buat perangkat yang dapat di boot dari Disk Image, termasuk yang Disk Image yang terkompresi","Crea unità avviabili da immagini disco avviabili, incluse quelle compresse","圧縮済みのものを含むディスクイメージから起動可能ドライブを作成します。","압축된 이미지를 포함하여 부팅 가능한 디스크 이미지에서 부팅 가능한 드라이브 만들기","Izveido ielādes ierīces no ielādes disku virtuālajiem attēliem, tai skaitā arī no saspiestajiem","Sukurkite įkrovos diskus iš įkrovos disko vaizdų, įskaitant suspaustus","Buat pemacu boleh boot daripada imej cakera boleh boot, termasuk yang dimampatkan","Lag oppstartbare disker fra images, inkludert komprimerte sådan","درایوهای قابل بوت را از تصاویر دیسک قابل بوت، از جمله موارد فشرده، ایجاد کنید","Twórz dyski rozruchowe z obrazów dysków, włączając skompresowane","Criar discos inicializáveis a partir de imagens de disco inicializáveis, inclusive de imagens compactadas","Criar unidades inicializáveis a partir de imagens de disco inicializáveis, inclusive de imagens compactadas","Crează drive-uri de la imagini de disc bootabile, incluzând cele compresate","Создать загрузочные диски из образов загрузочных дисков, в том числе сжатых","Kreiranje disk jedinica za pokretanje sistema sa slika diska koji se može pokretanja, uključujući kompresovane","Vytvorte bootovacie jednotky z diskových obrazov, vrátane tých komprimovaných","Ustvarite zagonske pogone iz slik diska, ki jih je mogoče zagnati, vključno s stisnjenimi","Cree unidades de arranque a partir de imágenes de disco de arranque, incluidas las comprimidas","Skapa startbara enheter från startbara diskavbildningar, inklusive komprimerade","สร้างไดร์ฟที่บูตได้จากดิสก์อิมเมจที่บูตได้ รวมไปถึงอันที่ถูกบีบอัด","Sıkıştırılmış olanlar da dahil olmak üzere önyüklenebilir disk yansısından önyüklenebilir sürücüler oluşturun","Створення завантажувальних пристроїв з завантажувальних образів, у тому числі стиснутих","Tạo ổ đĩa có thể khởi động từ các tệp đĩa có thể khởi động, bao gồm cả tệp nén"
"Feature5","704","Text","","Create BIOS or UEFI bootable drives, including UEFI bootable NTFS","إنشاء BIOS أو محركات أقراص UEFI قابلة للتمهيد ، بما في ذلك NTFS القابل للتشغيل من UEFI","Създаване на BIOS или UEFI стартиращи устройства, включително UEFI стартиращ NTFS","创建 BIOS 或 UEFI 可启动驱动器,包括 UEFI 可启动的 NTFS 驱动器","創建 BIOS 或 UEFI 可啟動驅動器,包括 UEFI 可啟動的 NTFS 驅動器","Stvaranje BIOS ili UEFI pogona za pokretanje, uključujući UEFI NTFS za pokretanje","Vytvořte zaváděcí jednotky BIOS nebo UEFI, včetně zaváděcích souborů NTFS UEFI","Lav BIOS eller UEFI opstartsbarer drev, inklusiv UEFI opstartsbarer NTFS","BIOS of UEFI opstartbare schijven aanmaken, inclusief UEFI opstartbare NTFS","Luo BIOS- tai UEFI-boottaavia asemia, mukaanlukien UEFI-boottaavat NTFS-asemat","Créez des disques amorçables BIOS ou UEFI, y compris des disques UEFI amorçables utilisant NTFS","Erstellen von BIOS- oder UEFI-bootfähigen Laufwerken, einschließlich UEFI-bootfähigem NTFS","Δημιουργήστε μονάδες δίσκου με δυνατότητα εκκίνησης BIOS ή UEFI, συμπεριλαμβανομένων NTFS με δυνατότητα εκκίνησης UEFI","יצירת כוננים הניתנים לאתחול ממחשבים התומכים ב־BIOS או UEFI, לרבות כוננים הניתנים לאתחול מ־UEFI, המשתמשים במערכת הקבצים NTFS","BIOS-ból vagy UEFI-ből bootolható meghajtók készítése, beleértve az UEFI-ből bootolható NTFS meghajtókat is","Buat perangkat BIOS atau UEFI yang dapat di boot, termasuk perangkat NTFS yang dapat di boot oleh UEFI","Crea unità avviabili BIOS o UEFI, incluso NTFS avviabile UEFI","UEFI:NTFSを含むBIOS及びUEFIで起動可能なドライブを作成します。","UEFI 부팅 가능한 NTFS를 포함하여 BIOS 또는 UEFI 부팅 가능 드라이브 만들기","Izveido BIOS vai UEFI ielādes ierīces, ieskaitot UEFI ielādi no NTFS","Sukurkite BIOS arba UEFI įkrovos diskus, įskaitant UEFI įkrovos NTFS","Buat pemacu boleh boot BIOS atau UEFI, termasuk NTFS boleh boot UEFI","Lag BIOS eller UEFI oppstartbare disker, inkludert UEFI oppstartbar NTFS","درایوهای قابل بوت بایوس یا UEFI از جمله NTFS قابل بوت UEFI ایجاد کنید","Stwórz dysk rozruchowy BIOS lub UEFI, włączając bootowalny dysk UEFI NTFS","Criar discos inicializáveis BIOS ou UEFI, inclusive discos UEFI inicializáveis usando NTFS","Criar discos inicializáveis BIOS ou UEFI, inclusive discos UEFI inicializáveis usando NTFS","Crează discuri bootabile BIOS sau UEFI, incluzând NTFS-uri bootabile de UEFI","Создать загрузочные диски BIOS или UEFI, включая загрузочный UEFI NTFS","Kreiranje BIOS ili UEFI disk jedinica za pokretanje sistema, uključujući NTFS sa UEFI pokretanjem sistema","Vytvorte bootovacie jednotky systému BIOS alebo UEFI vrátane UEFI bootovateľnej jednotky NTFS","Ustvarite zagonske pogone BIOS ali UEFI, vključno z UEFI bootable NTFS","Cree unidades de arranque BIOS o UEFI, incluido NTFS de arranque UEFI","Skapa BIOS- eller UEFI-startbara enheter, inklusive UEFI-startbar NTFS","สร้างไดร์ฟที่บูตได้จาก BIOS หรือ UEFI รวมไปถึง NTFS ที่บูตได้จาก UEFI","UEFI önyüklenebilir NTFS dahil BIOS ya da UEFI önyüklenebilir sürücüler oluşturun","Створення завантажувальних пристроїв BIOS чи UEFI, включаючи завантажувальний UEFI NTFS","Tạo ổ đĩa có thể khởi động với hệ thống BIOS hoặc UEFI, bao gồm cả NTFS có thể khởi động với UEFI"
"Feature6","705","Text","","Create 'Windows To Go' drives","إنشاء محركات أقراص ""Windows To Go\","Създаване на 'Windows To Go' устройства","创建 'Windows To Go' 驱动器","創建 'Windows To Go' 驅動","Stvaranje pogona ""Windows To Go\","Vytvoření jednotek ""Windows To Go","Lav 'Windows To Go' drev","'Windows To Go'-schijven aanmaken","Luo 'Windows To Go' -asemia","Créez des disques 'Windows To Go'","Erstellen von ""Windows To Go""-Laufwerken","Δημιουργήστε μονάδες δίσκου ""Windows To Go\","יצירת כונני Windows To Go","'Windows To Go' meghajtók készítése","Buat perangkat Windows To Go","Crea unità 'Windows To Go'","Windows To Goドライブを作成します。","'Windows To Go' 드라이브 만들기","Izveido 'Windows To Go' ierīces","Sukurkite ""Windows To Go"" diskus","Buat pemacu 'Windows To Go'","Lag 'Windows To Go' disker","درایوهای ""Windows To Go"" را ایجاد کنید","Stwórz dysk 'Windows To Go'","Criar discos 'Windows To Go'","Criar discos 'Windows To Go'","Crează discuri 'Windows To Go'","Создание дисков Windows To Go","Kreiranje disk jedinica ""Windows to Go\","Vytvorte jednotky „Windows To Go\","Ustvarjanje pogonov »Windows To Go'","Cree unidades 'Windows To Go'","Skapa 'Windows To Go'-enheter","สร้างไดร์ฟของ 'Windows To Go'","'Windows To Go' sürücüleri oluşturun","Створення пристроїв 'Windows To Go'","Tạo ổ đĩa 'Windows To Go'"
"Feature7","706","Text","","Create Windows 11 installation drives for PCs that don't have TPM or Secure Boot","قم بإنشاء محركات تثبيت ويندوز 11 لأجهزة الكمبيوتر التي لا تحتوي على TPM أو التمهيد الآمن","Създаване на Windows 11 инсталационно устройство за компютри, които нямат TPM или Secure Boot","为没有 TPM 或安全启动功能的电脑创建 Windows 11 安装驱动器","為沒有 TPM 或安全啟動功能的電腦創建 Windows 11 安裝驅動","Stvaranje instalacijskih pogona sustava Windows 11 za PC-jeve koji nemaju TPM ili Sigurno pokretanje","Vytvoření instalačních jednotek systému Windows 11 pro počítače bez čipu TPM nebo Secure Boot","Lav Windows 11 installations drev for PCer der ikker har TPM eller Secure Boot","Windows 11 installatieschijven aanmaken voor pc's die geen TPM of Secure Boot hebben","Luo Windows 11 -asennusasemia tietokoneille, jotka eivät tue TPM- tai Secure Boot -ominaisuuksia","Créez des disques d'installation Windows 11 pour des PCs qui ne disposent pas de TPM ou Secure Boot","Erstellen von Windows 11-Installationslaufwerken für PCs ohne TPM oder Secure Boot","Δημιουργήστε μονάδες εγκατάστασης των Windows 11 για υπολογιστές που δεν διαθέτουν TPM ή Ασφαλή Εκκίνηση","יצירת כונני התקנה של Windows 11 עבור מחשבים שאין להם TPM או Secure Boot","Windows 11 telepítési meghajtók készítése olyan PC-k számára, amelyek nem rendelkeznek TPM vagy Secure Boot funkciókkal","Buat perangkat pemasang Windows 11 untuk PC yang tidak mempunyai TPM atau Secure Boot","Crea unità di installazione di Windows 11 per PC che non dispongono di TPM o avvio protetto","TPM及びセキュアブート非対応のPC向けのWindows 11インストールドライブを作成します","TPM 또는 보안 부팅이 없는 PC용 Windows 11 설치 드라이브 만들기","Izveido Windows 11 instalācijas ierīces datoriem, kam nav TPM vai Secure Boot","Sukurkite Windows 11 diegimo diskus kompiuteriams, kuriuose nėra TPM arba saugaus įkrovimo","Buat pemacu pemasangan Windows 11 untuk PC yang tidak mempunyai TPM atau But Selamat","Lag oppstartsmedia for Windows 11 som ikke krever TPM eller Secure Boot","درایوهای نصب ویندوز 11 را برای رایانه هایی که TPM یا Secure Boot ندارند ایجاد کنید","Twórz dyski instalacyjne systemu Windows 11 dla komputerów, które nie posiadają modułu TPM ani Secure Boot","Criar discos de instalação do Windows 11 para PCs que não possuem TPM ou Secure Boot","Criar discos de instalação do Windows 11 para PCs que não possuem TPM ou Secure Boot","Crează drive de instalare Windows 11 pe computere care nu au TPM sau Bootare Securizată","Создать установочные диски Windows 11 для компьютеров без TPM или безопасной загрузки","Kreiranje windows 11 instalacionih disk jedinica za računare koji nemaju TPM ili bezbedno pokretanje sistema","Vytvorte inštalačné jednotky Windows 11 pre počítače, ktoré nemajú modul TPM, ani Secure Boot","Ustvarjanje namestitvenih pogonov za Windows 11 za računalnike, ki nimate TPM ali Varnega zagona","Cree unidades de instalación de Windows 11 para PC que no tienen TPM o Arranque seguro","Skapa installationsenheter till Windows 11 för datorer som inte har TPM eller säker start","สร้างไดร์ฟติดตั้ง Windows 11 สำหรับคอมพิวเตอร์ที่ไม่มี TPM หรือ SecureBoot","TPM ya da Güvenli Önyüklemeye sahip olmayan bilgisayarlar için Windows 11 kurulum sürücüleri oluşturun","Створення інсталяційних дисків Windows 11 для ПК, які не мають TPM чи Secure Boot","Tạo ổ đĩa cài đặt Windows 11 cho các máy tính không có TPM hoặc Secure Boot"
"Feature8","707","Text","","Create persistent Linux partitions","إنشاء Persistent Linux partitions","Създаване на устойчиви Linux дялове","创建持久 Linux 分区","創建持久 Linux 分區","Stvaranje trajnih Linux particija","Vytvoření trvalých oddílů systému Linux","Lav vedvarende Linux adskillelser","Persistent Linux partities aanmaken","Luo pysyviä Linux-osioita","Créez des partitions persistentes pour Linux","Persistente Linux-Partitionen erstellen","Δημιουργήστε μόνιμα διαμερίσματα Linux","יצירת מחיצות Linux קבועות","Tartós Linux partíciók készítése","Buat partisi Linux yang tetap/persistent","Crea partizioni persistenti Linux","記録用Linuxパーティションを作成します。","영구 리눅스 파티션 만들기","Izveido pastāvīgas Linux partīcijas","Sukurkite nuolatinius Linux skaidinius","Buat partition Linux berterusan","Lag persistente Linux partisjoner","ایجاد پارتیشن های لینوکس دائمی","Stwórz particje persistent Linuxa","Criar partições persistentes para Linux","Crie partições persistentes para Linux","Crează partiție de Linux persistentă","Создать постоянные разделы Linux","Kreiranje upornih Linux particija","Vytvorte trvalé oblasti systému Linux","Ustvarjanje trajnih Linux particij","Crear particiones persistentes de Linux","Skapa beständiga Linux-partitioner","สร้างพาร์ทิชั่นของ Linux แบบถาวร","Kalıcı Linux bölümleri oluşturun","Створення розділу збереження Linux","Tạo phân vùng Linux liên tục"
"Feature9","708","Text","","Create VHD/DD images of the selected drive","إنشاء صور VHD / DD لمحرك الأقراص المحدد","Създаване на VHD/DD образи на избраното устройство","为选择的驱动器创建 VHD/DD 镜像","為選中的驅動創建 VHD/DD 鏡像","Stvaranje VHD/DD slika odabranog pogona","Vytvoření obrazů VHD/DD z vybrané jednotky","Lav VHD/DD billeder af det valgte drev","VHD/DD-images van de geselecteerde schijf aanmaken","Luo VHD/DD-kuvia valitusta asemasta","Créez des images VHD/DD du périphérique sélectionné","VHD/DD-Images des ausgewählten Laufwerks erstellen","Δημιουργήστε εικόνες VHD/DD της επιλεγμένης μονάδας δίσκου","יצירת קובצי תמונה מסוג VHD/DD של הכונן שנבחר","VHD/DD képfájl készítése a kiválasztott meghajtóról","Buat image VHD/DD dari penyimpanan yang dipilih","Crea immagini VHD/DD dell'unità selezionata","選択されたドライブのVHD/DDイメージを作成します。","선택한 드라이브의 VHD/DD 이미지 만들기","Izveido izvēlētā diska VHD/DD virtuālos attēlus","Sukurkite pasirinkto disko VHD / DD vaizdus","Buat imej VHD/DD bagi pemacu yang dipilih","Lag VHD/DD speilinger av valgt disk","تصاویر VHD/DD از درایو انتخاب شده ایجاد کنید","Stwórz obraz VHD/DD z wybranego dysku","Criar imagens VHD/DD do dispositivo selecionado","Criar imagens VHD/DD do dispositivo selecionado","Crează imagini VHD/DD de pe drive-ul selectat","Создать образы VHD/DD выбранного диска","Kreiranje VHD/DD slika izabrane disk jedinice","Vytvorte obrazy VHD/DD z vybratej jednotky","Ustvarjanje VHD/DD slik izbranega pogona","Cree imágenes VHD/DD de la unidad seleccionada","Skapa VHD/DD-avbilder av den valda enheten","สร้างอิมเมจไฟล์แบบ VHD/DD ของไดร์ฟที่เลือก","Seçilen sürücünün VHD/DD yansılarını oluşturun","Створення образів VHD/DD з вибраних дисків","Tạo tệp VHD/DD từ ổ đĩa đã chọn"
"Feature10","709","Text","","Compute MD5, SHA-1, SHA-256 and SHA-512 checksums of the selected image","حساب المجموع الاختباري MD5 و SHA-1 و SHA-256 و SHA-512 للصورة المحددة","Изчисляване на MD5, SHA-1, SHA-256 и SHA-512 чексуми на избраният образ","计算被选择镜像的 MD5、SHA-1、SHA-256 和 SHA-512 校验码","計算被選中鏡像的 MD5、SHA-1、SHA-256 和 SHA-512 校驗碼","Izračunajte kontrolne zbrojeve odabrane slike MD5, SHA-1, SHA-256 i SHA-512","Výpočet kontrolních součtů MD5, SHA-1, SHA-256 a SHA-512 vybraného obrazu","Beregn MD5, SHA-1, SHA-256 og SHA-512 checksums af det valgte billede","MD5, SHA-1, SHA-256 en SHA-512 controlesommen berekenen van de geselecteerde image","Laske MD5, SHA-1, SHA-256 ja SHA-512 tarkistussummia valitusta levykuvasta","Calculez les sommes de contrôle MD5, SHA-1, SHA-256 et SHA-512 de l'image sélectionnée","Berechnung von MD5-, SHA-1-, SHA-256- und SHA-512-Prüfsummen für das ausgewählte Bild","Υπολογίστε τα αθροίσματα ελέγχου MD5, SHA-1, SHA-256 και SHA-512 της επιλεγμένης εικόνας","חישוב סיכומי ביקורת מסוג MD5, SHA-1, SHA-256 ו־SHA-512 של קובץ התמונה שנבחרה","A kiválasztott képfájl MD5, SHA-1, SHA-256 és SHA-512 ellenőrző összegének kiszámítása","Hitung checksum MD5, SHA-1, SHA-256 dan SHA-512 dari image yang dipilih","Calcola i checksum MD5, SHA-1, SHA-256 e SHA-512 dell'immagine selezionata","選択されたイメージのMD5、SHA-1、SHA-256及びSHA-512チェックサムを計算します。","선택한 이미지의 MD5, SHA-1, SHA-256 및 SHA-512 체크섬 계산","Izskaitļo izvēlētā virtuālā attēla MD5, SHA-1, SHA-256 un SHA-512 kontrolsummas","Apskaičiuokite pasirinkto vaizdo MD5, SHA-1, SHA-256 ir SHA-512 kontrolines sumas","Kira MD5, SHA-1, SHA-256 dan SHA-512 checksum imej yang dipilih","Kalkuler MD5, SHA-1, SHA-256 og SHA-512 sjekksummer fra valgt speiling","MD5، SHA-1، SHA-256 و SHA-512 را برای تصویر انتخابی محاسبه کنید","Oblicz sumy kontrolne MD5, SHA-1, SHA-256 i SHA-512 dla wybranego obrazu","Calcular somas de verificação MD5, SHA-1, SHA-256 e SHA-512 da imagem selecionada","Calcular checksums MD5, SHA-1, SHA-256 e SHA-512 da imagem selecionada","Compută MD5, SHA-1, SHA-256 și SHA-512 suma de control ale imaginilor selectate","Вычислить контрольные суммы MD5, SHA-1, SHA-256 и SHA-512 выбранного образа","Izračunajte MD5, SHA-1, SHA-256 i SHA-512 kontrolne preglede izabrane slike","Vypočítajte kontrolné súčty vybratého obrazu (MD5, SHA-1, SHA-256 a SHA-512)","Račun MD5, SHA-1, SHA-256 in SHA-512 kontrolni vsoti izbrane slike","Calcule las sumas de comprobación MD5, SHA-1, SHA-256 y SHA-512 de la imagen seleccionada","Beräkna kontrollsummor MD5, SHA-1, SHA-256 och SHA-512 för den valda avbilden","คำนวนรหัส MD5, SHA-1, SHA-256, SHA-512 ของไฟล์อิมเมจที่เลือก","Seçilen yansının MD5, SHA-1, SHA-256 ve SHA-512 sağlama toplamlarını hesaplayın","Обчислення контрольних сум MD5, SHA-1, SHA-256 та SHA-512 для вибраних образів","Tính tổng kiểm MD5, SHA-1, SHA-256 và SHA-512 của tệp đã chọn"
"Feature11","710","Text","","Perform bad blocks checks, including detection of ""fake"" flash drives","إجراء فحوصات كتل تالفة ، بما في ذلك الكشف عن محركات أقراص فلاش ""زائفة\","Проверяване за лоши блокове, включително засичане на ""фалшиви"" устройства","执行坏块检查包括对”假“U盘的检测","執行壞塊檢查包括對”假“USB 快閃磁碟機的檢測","Izvršite provjere loših blokova, uključujući otkrivanje ""lažnih"" flash pogona","Provést kontrolu vadných bloků, včetně detekce ""falešných"" bloků. flash disky","Udøv dårlige blokke tjeks, inklusiv opdagelse af ""falske"" flashdrev","Controles uitvoeren op slechte blokken, inclusief detectie van ""valse"" flashdrives","Suorita viallisten lohkojen tarkistuksia, sisältäen ""valheellisten"" muistitikkujen tunnistamisen","Executez un test de mauvais secteurs avec detection des ""fake drives\","Durchführung von Prüfungen auf fehlerhafte Blöcke, einschließlich der Erkennung von ""gefälschten"" Flash-Laufwerken","Εκτελέστε ελέγχους εσφαλμένων block, συμπεριλαμβανομένου του εντοπισμού ""ψευδών"" μονάδων flash","ביצוע בדיקות אחר בלוקים (אזורים) פגומים, כולל זיהוי של כונני הבזק ""מזוייפים\","Hibás blokkok ellenőrzése, beleértve a ""hamis"" flash meghajtók detektálását","Lakukan cek Blok yang buruk, termasuk deteksi USB Flash Disk ""PALSU\","Esegui controlli dei blocchi danneggiati, incluso il rilevamento di unità flash ""false\","不良ブロックチェック及び容量詐欺ドライブの検知を行います。","""위조"" 플래시 드라이브 감지를 포함하여 불량 블록 검사 수행","Izpilda bojāto bloku pārbaudi ieskaitot ""falsificēto"" nesēju noteikšanu","Atlikite blogų blokų patikrinimus, įskaitant ""netikrų"" flash diskų aptikimą","Melakukan pemeriksaan blok buruk, termasuk pengesanan pemacu kilat ""palsu\","Utfør sjekk for dårlige sektorer, inkludert sjekk for forfalskede flash disker","بررسی بلوک های بد، از جمله تشخیص درایوهای فلش ""جعلی"" را انجام دهید","Sprawdź dysk pod względem spójności danych lub wykryj ""nieorginalny"" pendrive","Executar verificações de blocos defeituosos, incluindo detecção de unidades flash ""falsificadas\","Executar verificações de blocos inválidos, incluindo a detecção de unidades flash ""falsas\","Verifică blocuri rele, incluzând detectarea de drive-uri flash ""false\","Проверить наличие плохих блоков, обнаружить ""поддельные"" флешки","Izvršite provere loših blokova, uključujući otkrivanje ""lažnih"" fleš diskova","Vykonajte kontroly zlých blokov vrátane detekcie „falošných"" prenosných diskov","Izvajanje preverjanj slabih blokov, vključno z odkrivanjem »lažnih« bliskavic","Realice comprobaciones de bloques defectuosos, incluida la detección de unidades flash ""falsas\","Utför kontroll av trasiga block, inklusive upptäckt av ""falska"" USB-minnen","ดำเนินการตรวจสอบบล็อกข้อมูลที่พัง รวมไปถึงการทดสอบว่าเป็นแฟลชไดร์ฟ ""ปลอม"" หรือไม่","""Sahte"" flash sürücülerin tespiti de dahil olmak üzere hatalı blok kontrolleri gerçekleştirin","Перевірка дисків (включаючи фальшиві диски)","Thực hiện kiểm tra điểm lỗi, bao gồm phát hiện ổ đĩa ""giả\"
"Feature12","711","Text","","Download official Microsoft Windows retail ISOs","قم بتنزيل ملفات ISO الرسمية الخاصة بـ Microsoft Windows","Изтегляне на официални Microsoft Windows ISO образи","下载微软官方 Windows 镜像","下載微軟官方 Windows 鏡像","Preuzimanje službenih ISO-ova za maloprodaju sustava Microsoft Windows","Stažení oficiálních souborů ISO systému Microsoft Windows","Hent officielle Microsoft Windows detail ISOer","Officiële Microsoft Windows retail ISO's downloaden","Lataa virallisia Microsoft Windowsin jälleenmyyntiversion ISO-levykuvia","Téléchargez des images ISOs commerciales officielles de Microsoft Windows","Offizielle Microsoft Windows-ISOs herunterladen","Κατεβάστε τα επίσημα retail ISO των Microsoft Windows","הורדת קובצי ה־ISO הקמעונאיים הרשמיים של Microsoft Windows","Hivatalos Microsoft Windows kiskereskedelmi ISO képfájlok letöltése","Unduh ISO Microsoft Windows resmi","Scarica le ISO ufficiali di Microsoft Windows","マイクロソフト公式のWindows ISOをダウンロードします。","공식 Microsoft Windows 리테일 ISO 다운로드","Lejupielādē oficiālos Microsoft ISO failus","Atsisiųskite oficialius Microsoft Windows mažmeninės prekybos ISO","Muat turun rasmi ISO runcit Microsoft Windows","Last ned offisielle Windows ISOer","ISO های رسمی ماکروسافت را دریافت کنید","Pobierz oficjalny obraz ISO systemu Microsoft Windows","Baixar ISOs oficiais do Microsoft Windows","Transferir ISOs oficiais do Microsoft Windows Retail","Descarcă un Microsoft Windows ISO oficial de vânzare","Загрузить официальные ISO-образы Windows","Preuzmite zvanične Microsoft Windows maloprodajne ISO-ove","Stiahnite si oficiálne ISO pre Microsoft Windows","Prenos uradnih Microsoft Windows maloprodaja ISOs","Descargue los ISO oficiales de Microsoft Windows","Ladda ner officiella Microsoft Windows ISO-filer","ดาวน์โหลดอิมเมจไฟล์ของ Windows จากเว็บไซต์ทางการ","Resmi Microsoft Windows Retail ISO'larını indirin","Завантаження офіційних образів Microsoft Windows","Tải xuống các tệp Microsoft Windows ISO bán lẻ chính thức"
"Feature13","712","Text","","Download UEFI Shell ISOs","قم بتنزيل UEFI Shell ISOs","Изтегляне на UEFI Shell образи","下载 UEFI Shell 镜像","下載 UEFI Shell 鏡像","Preuzmite ISO-ove UEFI ljuske","Stažení souborů UEFI Shell ISO","Hent UEFI Shell ISOer","UEFI Shell ISO's downloaden","Lataa UEFI Shell ISO-levykuvia","Téléchargez des images ISOs du Shell UEFI","UEFI-Shell-ISOs herunterladen","Κατεβάστε τα ISO Shell UEFI","הורדת קובצי ISO של מעטפת UEFI","UEFI Shell ISO képfájlok letöltése","Unduh Shell ISO UEFI","Scarica le ISO della shell UEFI","UEFIシェルのISOをダウンロードします。","UEFI Shell ISO 다운로드","Lejupielādē UEFI OS ISO failus","Atsisiųskite UEFI Shell ISO","Muat turun ISO Shell UEFI","Last ned UEFI kommandolinje ISOer","ISO های پوسته UEFI را دانلود کنید","Ściągnij obrazy ISO UEFI Shell","Baixar ISOs do Shell UEFI","Transferir ISOs de UEFI Shell","Descarcă UEFI Shell ISO-uri","Загрузить ISO-образы оболочки UEFI","Preuzmite UEFI Shell ISOs","Stiahnite UEFI Shell ISO","Prenos UEFI Shell ISOs","Descargar ISO de UEFI Shell","Ladda ner UEFI-shell ISO-filer","ดาวน์โหลดอิมเมจไฟล์ของ UEFI Shell","UEFI Shell ISO'larını indirin","Завантаження командної оболонки UEFI ISO","Tải xuống các tệp UEFI Shell ISO"
"Feature1","700","Text","","Format USB, flash card and virtual drives to FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3","تهيئة USB وبطاقة الفلاش ومحركات الأقراص الافتراضية إلى FAT / FAT32 / NTFS / UDF / exFAT / ReFS / ext2 / ext3","Форматиране на USB, карти памет и виртуални устройства с FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3","将 U 盘、存储卡或虚拟驱动器格式化为 FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3 格式","將隨身碟、記憶卡或虛擬光碟機格式化為 FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3 格式","Formatirajte USB, flash karticu i virtualne pogone na FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3","Formátování USB, flash karet a virtuálních jednotek na FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3","Formater USB, flash kort og virtuelle drev til FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3","USB, flashkaart en virtuele schijven formatteren naar FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3","Alusta USB-asemia, muistikortteja ja virtuaalisia asemia muotoon FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3","Formatez des périphériques USB, des cartes flash et des disques virtuels en FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3","Formatieren von USB, Flash-Karte und virtuellen Laufwerken in FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3","Μορφοποίηση USB, κάρτας flash και εικονικών μονάδων δίσκου σε FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3","אתחול USB, כרטיסי זיכרון וכוננים וירטואליים ל־FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3","USB, flash memóriakártyák és virtuális meghajtók formázása FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3 fájlrendszerre","Format USB, kartu flash dan penyimpanan maya ke FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3","Formatta USB, flash card e unità virtuali in FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3","USBメモリやSDカード、仮想ドライブをFAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3でフォーマットします。","USB, 플래시 카드 및 가상 드라이브를 FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3로 포맷","Formatē USB, atmiņas kartes un virtuālos diskus formātos FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3","Suformatuokite USB, flash kortelę ir virtualius diskus į FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3","Formatkan USB, kad flash dan pemacu maya kepada FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3","Formater USB, minnekort og virtuelle disker til FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3","فرمت USB، فلش کارت و درایوهای مجازی به FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3","Sformatuj nośnik używając: FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3","Formatar dispositivos USB, cartões flash e discos virtuais com FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3","Formatar dispositivos USB, cartão de memória e drives virtuais em FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3","Formatează USB, card flash si drive-uri virtuale la FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3","Форматировать USB, флешки и виртуальные диски в FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3","Formatiraj USB, flash kartice, i virtualne diskove u FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3","Naformátujte USB, kartu a virtuálne disky do FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3","FormatIRANJE USB, bliskavice in virtualnih pogonov na FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3","Formatee USB, tarjetas flash y unidades virtuales a FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3","Formatera USB-enheter, flash-kort och virtuella enheter till FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3","ฟอร์แมต USB, แฟลชการ์ด หรือไดร์ฟจำลองให้อยู่ในรูปแบบของ FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3","USB, flash kart ve sanal sürücüleri FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3 olarak biçimlendirin","Форматування USB-накопичувачів, флешок, карток пам'яті у FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3","Định dạng USB, thẻ nhớ hoặc ổ nhớ ảo với FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3"
"Feature2","701","Text","","Create FreeDOS bootable USB drives","إنشاء محركات أقراص USB قابلة للتشغيل من FreeDOS","Създаване на FreeDOS стартиращ USB устройства","创建 FreeDOS 可启动驱动器","建立 FreeDOS 可啟隨身碟","Stvaranje FreeDOS USB pogona za pokretanje","Vytvoření bootovacích disků USB se systémem FreeDOS","Lav FreeDOS opstartsbare USB drev","FreeDOS opstartbare USB-schijven aanmaken","Luo boottaavia FreeDOS USB-asemia","Créez des disques amorçable FreeDOS","FreeDOS-bootfähige USB-Laufwerke erstellen","Δημιουργήστε μονάδες USB με δυνατότητα εκκίνησης FreeDOS","יצירת כונני USB הניתנים לאתחול של FreeDOS","Bootolható FreeDOS USB meghajtó készítése","Buat perangkat USB FreeDOS yang dapat di boot","Crea unità USB avviabili FreeDOS","FreeDOSの起動可能ドライブを作成します。","FreeDOS 부팅 가능한 USB 드라이브 만들기","Izveido FreeDOS ielādes USB ierīces","Sukurkite FreeDOS įkrovos USB diskus","Buat pemacu USB boleh boot FreeDOS","Lag FreeDos oppstartbar USB stick","درایوهای USB قابل بوت FreeDOS را ایجاد کنید","Stwórz bootowalny nośnik USB FreeDOS","Criar discos USB inicializáveis FreeDOS","Criar unidades USB inicializáveis FreeDOS","Crează drive USB bootabil FreeDOS","Создать загрузочные USB-диски FreeDOS","Kreiraj FreeDOS butabilni USB disk","Vytvorte bootovacie usb zariadenia FreeDOS","Ustvarite FreeDOS zagonske USB pogone","Crear unidades USB de arranque FreeDOS","Skapa FreeDOS startbara USB-enheter","สร้าง USB ไดร์ฟที่บูตได้สำหรับระบบ FreeDOS","FreeDOS önyüklenebilir USB sürücüleri oluşturun","Створення завантажувальних пристроїв FreeDOS","Tạo USB có thể khởi động với FreeDOS"
"Feature3","702","Text","","Create bootable drives from bootable ISOs (Windows, Linux, etc.)","إنشاء محركات أقراص قابلة للتمهيد من ملفات ISO القابلة للتمهيد (Windows و Linux وما إلى ذلك)","Създаване на стартиращи устройства от ISO образи (Windows, Linux и др.)","从可启动 ISO 文件 (Windows 和 Linux 等) 创建可启动驱动器","從可啟動 ISO 檔案 (Windows 和 Linux 等) 建立可啟動隨身碟","Stvaranje pogona za pokretanje iz ISO-ova za pokretanje (Windows, Linux itd.)","Vytváření bootovacích jednotek ze zaváděcích ISO (Windows, Linux atd.)","Lav opstartsbarer drev fra opstartsbarer ISOer (Window, Linux, osv.)","Opstartbare schijven aanmaken via opstartbare ISO's (Windows, Linux, enz)","Luo käynnistysasemia boottaavista ISO-kuvista (Windows, Linux jne.)","Créez des disques amorçables à partir d'images ISOs (Windows, Linux, etc.)","Erstellen bootfähiger Laufwerke aus bootfähigen ISOs (Windows, Linux, etc.)","Δημιουργήστε εκκινήσιμες μονάδες από ISO με δυνατότητα εκκίνησης (Windows, Linux, κ.λπ.)","יצירת כוננים הניתנים לאתחול מקובצי ISO הניתנים לאתחול (Windows, Linux וכו')","Bootolható meghajtók készítése bootolható ISO képfájlokból (Windows, Linux, stb.)","Buat perangkat yang dapat di boot dari ISO (Windows, Linux, dll.)","Crea unità avviabili da ISO avviabili (Windows, Linux, ecc.)","WindowsやLinuxなどのISOファイルから起動可能ドライブを作成します。","부팅 가능한 ISO (Windows, Linux 등)에서 부팅 가능한 드라이브 만들기","Izveido ielādes ierīces no ISO failiem (Windows, Linux, u.c.)","Sukurkite įkrovos diskus iš įkrovos ISO (Windows, Linux ir kt.)","Buat pemacu boleh boot daripada ISO boleh boot (Windows, Linux, dll.)","Lag oppstartabar enhet/disk fra ISOer (Windows, Linux, etc.)","ایجاد درایوهای قابل بوت از ISOهای قابل بوت (ویندوز، لینوکس و غیره)","Twórz dyski rozruchowe z obrazów ISO (Windows, Linux itp.)","Criar discos inicializáveis a partir de ISOs inicializáveis (Windows, Linux, etc.)","Criar unidades inicializáveis a partir de ISOs inicializáveis (Windows, Linux, etc.)","Crează drive-uri bootabile de la ISO-uri bootabile (Windows, Linux, etc.)","Создать загрузочные диски из загрузочных ISO-образов (Windows, Linux и т.д.)","Kreirajte disk jedinice za pokretanje sistema od ISO-a koji se mogu pokretanja sistema (Windows, Linux itd.)","Vytvorte bootovacie jednotky z ISO súborov (Windows, Linux atď.)","Ustvarite zagonske pogone iz zagonskih ISO-jev (Windows, Linux itd.)","Cree unidades de arranque desde ISO de arranque (Windows, Linux, etc.)","Skapa startbara enheter från startbara ISO-filer (Windows, Linux, etc.)","สร้าง USB ไดร์ฟที่บูตได้จากไฟล์อิมเมจที่บูตได้ (เช่น ไฟล์ติดตั้ง Windows หรือ Linux เป็นต้น)","Önyüklenebilir ISO'lardan önyüklenebilir sürücüler oluşturun (Windows, Linux, vb.)","Створення завантажувальних пристроїв з завантажувальних образів (Windows, Linux, тощо)","Tạo ổ đĩa có thể khởi động từ các file ISO có thể khởi động (Windows, Linux, v.v...)"
"Feature4","703","Text","","Create bootable drives from bootable disk images, including compressed ones","إنشاء محركات أقراص قابلة للتمهيد من صور الأقراص القابلة للتمهيد ، بما في ذلك الأقراص المضغوطة","Създаване на стартиращи устройства от образи, включително компресирани такива","从可启动硬盘镜像 (包括压缩镜像) 创建可启动驱动器","從可啟動硬碟映像檔 (包括壓縮映像檔) 建立可啟動隨身碟","Stvaranje pogona za pokretanje iz slika diska za pokretanje, uključujući komprimirane","Vytváření zaváděcích jednotek ze zaváděcích obrazů disků, včetně komprimovaných","Lav opstartsbarer drev fra opstartsbarer disk billeder, inklusiv komprimerede billeder","Opstartbare schijven aanmaken van opstartbare schijf-images, inclusief gecomprimeerde images","Luo käynnistysasemia boottaavista levykuvista, pakatut kuvat mukaanlukien","Créez des disques amorçables à partir d'images disque, y compris à partir d'images compressées","Erstellen bootfähiger Laufwerke aus bootfähigen Festplatten-Images, einschließlich komprimierter Images","Δημιουργήστε μονάδες εκκίνησης από εικόνες δίσκου με δυνατότητα εκκίνησης, συμπεριλαμβανομένων συμπιεσμένων","יצירת כוננים הניתנים לאתחול מקובצי תמונת דיסק הניתנים לאתחול, כולל קבצים דחוסים","Bootolható meghajtók készítése bootolható lemez képfájlokból, beleértve a tömörítetteket is","Buat perangkat yang dapat di boot dari Disk Image, termasuk yang Disk Image yang terkompresi","Crea unità avviabili da immagini disco avviabili, incluse quelle compresse","圧縮済みのものを含むディスクイメージから起動可能ドライブを作成します。","압축된 이미지를 포함하여 부팅 가능한 디스크 이미지에서 부팅 가능한 드라이브 만들기","Izveido ielādes ierīces no ielādes disku virtuālajiem attēliem, tai skaitā arī no saspiestajiem","Sukurkite įkrovos diskus iš įkrovos disko vaizdų, įskaitant suspaustus","Buat pemacu boleh boot daripada imej cakera boleh boot, termasuk yang dimampatkan","Lag oppstartbare disker fra images, inkludert komprimerte sådan","درایوهای قابل بوت را از تصاویر دیسک قابل بوت، از جمله موارد فشرده، ایجاد کنید","Twórz dyski rozruchowe z obrazów dysków, włączając skompresowane","Criar discos inicializáveis a partir de imagens de disco inicializáveis, inclusive de imagens compactadas","Criar unidades inicializáveis a partir de imagens de disco inicializáveis, inclusive de imagens compactadas","Crează drive-uri de la imagini de disc bootabile, incluzând cele compresate","Создать загрузочные диски из образов загрузочных дисков, в том числе сжатых","Kreiranje disk jedinica za pokretanje sistema sa slika diska koji se može pokretanja, uključujući kompresovane","Vytvorte bootovacie jednotky z diskových obrazov, vrátane tých komprimovaných","Ustvarite zagonske pogone iz slik diska, ki jih je mogoče zagnati, vključno s stisnjenimi","Cree unidades de arranque a partir de imágenes de disco de arranque, incluidas las comprimidas","Skapa startbara enheter från startbara diskavbildningar, inklusive komprimerade","สร้างไดร์ฟที่บูตได้จากดิสก์อิมเมจที่บูตได้ รวมไปถึงอันที่ถูกบีบอัด","Sıkıştırılmış olanlar da dahil olmak üzere önyüklenebilir disk yansısından önyüklenebilir sürücüler oluşturun","Створення завантажувальних пристроїв з завантажувальних образів, у тому числі стиснутих","Tạo ổ đĩa có thể khởi động từ các tệp đĩa có thể khởi động, bao gồm cả tệp nén"
"Feature5","704","Text","","Create BIOS or UEFI bootable drives, including UEFI bootable NTFS","إنشاء BIOS أو محركات أقراص UEFI قابلة للتمهيد ، بما في ذلك NTFS القابل للتشغيل من UEFI","Създаване на BIOS или UEFI стартиращи устройства, включително UEFI стартиращ NTFS","创建 BIOS 或 UEFI 可启动驱动器,包括 UEFI 可启动的 NTFS 驱动器","建立 BIOS 或 UEFI 可啟動隨身碟,包括 UEFI 可啟動的 NTFS 隨身碟","Stvaranje BIOS ili UEFI pogona za pokretanje, uključujući UEFI NTFS za pokretanje","Vytvořte zaváděcí jednotky BIOS nebo UEFI, včetně zaváděcích souborů NTFS UEFI","Lav BIOS eller UEFI opstartsbarer drev, inklusiv UEFI opstartsbarer NTFS","BIOS of UEFI opstartbare schijven aanmaken, inclusief UEFI opstartbare NTFS","Luo BIOS- tai UEFI-boottaavia asemia, mukaanlukien UEFI-boottaavat NTFS-asemat","Créez des disques amorçables BIOS ou UEFI, y compris des disques UEFI amorçables utilisant NTFS","Erstellen von BIOS- oder UEFI-bootfähigen Laufwerken, einschließlich UEFI-bootfähigem NTFS","Δημιουργήστε μονάδες δίσκου με δυνατότητα εκκίνησης BIOS ή UEFI, συμπεριλαμβανομένων NTFS με δυνατότητα εκκίνησης UEFI","יצירת כוננים הניתנים לאתחול ממחשבים התומכים ב־BIOS או UEFI, לרבות כוננים הניתנים לאתחול מ־UEFI, המשתמשים במערכת הקבצים NTFS","BIOS-ból vagy UEFI-ből bootolható meghajtók készítése, beleértve az UEFI-ből bootolható NTFS meghajtókat is","Buat perangkat BIOS atau UEFI yang dapat di boot, termasuk perangkat NTFS yang dapat di boot oleh UEFI","Crea unità avviabili BIOS o UEFI, incluso NTFS avviabile UEFI","UEFI:NTFSを含むBIOS及びUEFIで起動可能なドライブを作成します。","UEFI 부팅 가능한 NTFS를 포함하여 BIOS 또는 UEFI 부팅 가능 드라이브 만들기","Izveido BIOS vai UEFI ielādes ierīces, ieskaitot UEFI ielādi no NTFS","Sukurkite BIOS arba UEFI įkrovos diskus, įskaitant UEFI įkrovos NTFS","Buat pemacu boleh boot BIOS atau UEFI, termasuk NTFS boleh boot UEFI","Lag BIOS eller UEFI oppstartbare disker, inkludert UEFI oppstartbar NTFS","درایوهای قابل بوت بایوس یا UEFI از جمله NTFS قابل بوت UEFI ایجاد کنید","Stwórz dysk rozruchowy BIOS lub UEFI, włączając bootowalny dysk UEFI NTFS","Criar discos inicializáveis BIOS ou UEFI, inclusive discos UEFI inicializáveis usando NTFS","Criar discos inicializáveis BIOS ou UEFI, inclusive discos UEFI inicializáveis usando NTFS","Crează discuri bootabile BIOS sau UEFI, incluzând NTFS-uri bootabile de UEFI","Создать загрузочные диски BIOS или UEFI, включая загрузочный UEFI NTFS","Kreiranje BIOS ili UEFI disk jedinica za pokretanje sistema, uključujući NTFS sa UEFI pokretanjem sistema","Vytvorte bootovacie jednotky systému BIOS alebo UEFI vrátane UEFI bootovateľnej jednotky NTFS","Ustvarite zagonske pogone BIOS ali UEFI, vključno z UEFI bootable NTFS","Cree unidades de arranque BIOS o UEFI, incluido NTFS de arranque UEFI","Skapa BIOS- eller UEFI-startbara enheter, inklusive UEFI-startbar NTFS","สร้างไดร์ฟที่บูตได้จาก BIOS หรือ UEFI รวมไปถึง NTFS ที่บูตได้จาก UEFI","UEFI önyüklenebilir NTFS dahil BIOS ya da UEFI önyüklenebilir sürücüler oluşturun","Створення завантажувальних пристроїв BIOS чи UEFI, включаючи завантажувальний UEFI NTFS","Tạo ổ đĩa có thể khởi động với hệ thống BIOS hoặc UEFI, bao gồm cả NTFS có thể khởi động với UEFI"
"Feature6","705","Text","","Create 'Windows To Go' drives","إنشاء محركات أقراص ""Windows To Go\","Създаване на 'Windows To Go' устройства","创建 'Windows To Go' 驱动器","建立 'Windows To Go' 隨身碟","Stvaranje pogona ""Windows To Go\","Vytvoření jednotek ""Windows To Go","Lav 'Windows To Go' drev","'Windows To Go'-schijven aanmaken","Luo 'Windows To Go' -asemia","Créez des disques 'Windows To Go'","Erstellen von ""Windows To Go""-Laufwerken","Δημιουργήστε μονάδες δίσκου ""Windows To Go\","יצירת כונני Windows To Go","'Windows To Go' meghajtók készítése","Buat perangkat Windows To Go","Crea unità 'Windows To Go'","Windows To Goドライブを作成します。","'Windows To Go' 드라이브 만들기","Izveido 'Windows To Go' ierīces","Sukurkite ""Windows To Go"" diskus","Buat pemacu 'Windows To Go'","Lag 'Windows To Go' disker","درایوهای ""Windows To Go"" را ایجاد کنید","Stwórz dysk 'Windows To Go'","Criar discos 'Windows To Go'","Criar discos 'Windows To Go'","Crează discuri 'Windows To Go'","Создание дисков Windows To Go","Kreiranje disk jedinica ""Windows to Go\","Vytvorte jednotky „Windows To Go\","Ustvarjanje pogonov »Windows To Go'","Cree unidades 'Windows To Go'","Skapa 'Windows To Go'-enheter","สร้างไดร์ฟของ 'Windows To Go'","'Windows To Go' sürücüleri oluşturun","Створення пристроїв 'Windows To Go'","Tạo ổ đĩa 'Windows To Go'"
"Feature7","706","Text","","Create Windows 11 installation drives for PCs that don't have TPM or Secure Boot","قم بإنشاء محركات تثبيت ويندوز 11 لأجهزة الكمبيوتر التي لا تحتوي على TPM أو التمهيد الآمن","Създаване на Windows 11 инсталационно устройство за компютри, които нямат TPM или Secure Boot","为没有 TPM 或安全启动功能的电脑创建 Windows 11 安装驱动器","為沒有 TPM 或安全開機功能的電腦建立 Windows 11 安裝隨身碟","Stvaranje instalacijskih pogona sustava Windows 11 za PC-jeve koji nemaju TPM ili Sigurno pokretanje","Vytvoření instalačních jednotek systému Windows 11 pro počítače bez čipu TPM nebo Secure Boot","Lav Windows 11 installations drev for PCer der ikker har TPM eller Secure Boot","Windows 11 installatieschijven aanmaken voor pc's die geen TPM of Secure Boot hebben","Luo Windows 11 -asennusasemia tietokoneille, jotka eivät tue TPM- tai Secure Boot -ominaisuuksia","Créez des disques d'installation Windows 11 pour des PCs qui ne disposent pas de TPM ou Secure Boot","Erstellen von Windows 11-Installationslaufwerken für PCs ohne TPM oder Secure Boot","Δημιουργήστε μονάδες εγκατάστασης των Windows 11 για υπολογιστές που δεν διαθέτουν TPM ή Ασφαλή Εκκίνηση","יצירת כונני התקנה של Windows 11 עבור מחשבים שאין להם TPM או Secure Boot","Windows 11 telepítési meghajtók készítése olyan PC-k számára, amelyek nem rendelkeznek TPM vagy Secure Boot funkciókkal","Buat perangkat pemasang Windows 11 untuk PC yang tidak mempunyai TPM atau Secure Boot","Crea unità di installazione di Windows 11 per PC che non dispongono di TPM o avvio protetto","TPM及びセキュアブート非対応のPC向けのWindows 11インストールドライブを作成します","TPM 또는 보안 부팅이 없는 PC용 Windows 11 설치 드라이브 만들기","Izveido Windows 11 instalācijas ierīces datoriem, kam nav TPM vai Secure Boot","Sukurkite Windows 11 diegimo diskus kompiuteriams, kuriuose nėra TPM arba saugaus įkrovimo","Buat pemacu pemasangan Windows 11 untuk PC yang tidak mempunyai TPM atau But Selamat","Lag oppstartsmedia for Windows 11 som ikke krever TPM eller Secure Boot","درایوهای نصب ویندوز 11 را برای رایانه هایی که TPM یا Secure Boot ندارند ایجاد کنید","Twórz dyski instalacyjne systemu Windows 11 dla komputerów, które nie posiadają modułu TPM ani Secure Boot","Criar discos de instalação do Windows 11 para PCs que não possuem TPM ou Secure Boot","Criar discos de instalação do Windows 11 para PCs que não possuem TPM ou Secure Boot","Crează drive de instalare Windows 11 pe computere care nu au TPM sau Bootare Securizată","Создать установочные диски Windows 11 для компьютеров без TPM или безопасной загрузки","Kreiranje windows 11 instalacionih disk jedinica za računare koji nemaju TPM ili bezbedno pokretanje sistema","Vytvorte inštalačné jednotky Windows 11 pre počítače, ktoré nemajú modul TPM, ani Secure Boot","Ustvarjanje namestitvenih pogonov za Windows 11 za računalnike, ki nimate TPM ali Varnega zagona","Cree unidades de instalación de Windows 11 para PC que no tienen TPM o Arranque seguro","Skapa installationsenheter till Windows 11 för datorer som inte har TPM eller säker start","สร้างไดร์ฟติดตั้ง Windows 11 สำหรับคอมพิวเตอร์ที่ไม่มี TPM หรือ SecureBoot","TPM ya da Güvenli Önyüklemeye sahip olmayan bilgisayarlar için Windows 11 kurulum sürücüleri oluşturun","Створення інсталяційних дисків Windows 11 для ПК, які не мають TPM чи Secure Boot","Tạo ổ đĩa cài đặt Windows 11 cho các máy tính không có TPM hoặc Secure Boot"
"Feature8","707","Text","","Create persistent Linux partitions","إنشاء Persistent Linux partitions","Създаване на устойчиви Linux дялове","创建持久 Linux 分区","建立持續性 Linux 磁區","Stvaranje trajnih Linux particija","Vytvoření trvalých oddílů systému Linux","Lav vedvarende Linux adskillelser","Persistent Linux partities aanmaken","Luo pysyviä Linux-osioita","Créez des partitions persistentes pour Linux","Persistente Linux-Partitionen erstellen","Δημιουργήστε μόνιμα διαμερίσματα Linux","יצירת מחיצות Linux קבועות","Tartós Linux partíciók készítése","Buat partisi Linux yang tetap/persistent","Crea partizioni persistenti Linux","記録用Linuxパーティションを作成します。","영구 리눅스 파티션 만들기","Izveido pastāvīgas Linux partīcijas","Sukurkite nuolatinius Linux skaidinius","Buat partition Linux berterusan","Lag persistente Linux partisjoner","ایجاد پارتیشن های لینوکس دائمی","Stwórz particje persistent Linuxa","Criar partições persistentes para Linux","Crie partições persistentes para Linux","Crează partiție de Linux persistentă","Создать постоянные разделы Linux","Kreiranje upornih Linux particija","Vytvorte trvalé oblasti systému Linux","Ustvarjanje trajnih Linux particij","Crear particiones persistentes de Linux","Skapa beständiga Linux-partitioner","สร้างพาร์ทิชั่นของ Linux แบบถาวร","Kalıcı Linux bölümleri oluşturun","Створення розділу збереження Linux","Tạo phân vùng Linux liên tục"
"Feature9","708","Text","","Create VHD/DD images of the selected drive","إنشاء صور VHD / DD لمحرك الأقراص المحدد","Създаване на VHD/DD образи на избраното устройство","为选择的驱动器创建 VHD/DD 镜像","為選中的磁碟機建立 VHD/DD 映像檔","Stvaranje VHD/DD slika odabranog pogona","Vytvoření obrazů VHD/DD z vybrané jednotky","Lav VHD/DD billeder af det valgte drev","VHD/DD-images van de geselecteerde schijf aanmaken","Luo VHD/DD-kuvia valitusta asemasta","Créez des images VHD/DD du périphérique sélectionné","VHD/DD-Images des ausgewählten Laufwerks erstellen","Δημιουργήστε εικόνες VHD/DD της επιλεγμένης μονάδας δίσκου","יצירת קובצי תמונה מסוג VHD/DD של הכונן שנבחר","VHD/DD képfájl készítése a kiválasztott meghajtóról","Buat image VHD/DD dari penyimpanan yang dipilih","Crea immagini VHD/DD dell'unità selezionata","選択されたドライブのVHD/DDイメージを作成します。","선택한 드라이브의 VHD/DD 이미지 만들기","Izveido izvēlētā diska VHD/DD virtuālos attēlus","Sukurkite pasirinkto disko VHD / DD vaizdus","Buat imej VHD/DD bagi pemacu yang dipilih","Lag VHD/DD speilinger av valgt disk","تصاویر VHD/DD از درایو انتخاب شده ایجاد کنید","Stwórz obraz VHD/DD z wybranego dysku","Criar imagens VHD/DD do dispositivo selecionado","Criar imagens VHD/DD do dispositivo selecionado","Crează imagini VHD/DD de pe drive-ul selectat","Создать образы VHD/DD выбранного диска","Kreiranje VHD/DD slika izabrane disk jedinice","Vytvorte obrazy VHD/DD z vybratej jednotky","Ustvarjanje VHD/DD slik izbranega pogona","Cree imágenes VHD/DD de la unidad seleccionada","Skapa VHD/DD-avbilder av den valda enheten","สร้างอิมเมจไฟล์แบบ VHD/DD ของไดร์ฟที่เลือก","Seçilen sürücünün VHD/DD yansılarını oluşturun","Створення образів VHD/DD з вибраних дисків","Tạo tệp VHD/DD từ ổ đĩa đã chọn"
"Feature10","709","Text","","Compute MD5, SHA-1, SHA-256 and SHA-512 checksums of the selected image","حساب المجموع الاختباري MD5 و SHA-1 و SHA-256 و SHA-512 للصورة المحددة","Изчисляване на MD5, SHA-1, SHA-256 и SHA-512 чексуми на избраният образ","计算被选择镜像的 MD5、SHA-1、SHA-256 和 SHA-512 校验码","計算被選中映像的 MD5、SHA-1、SHA-256 和 SHA-512 檢查碼","Izračunajte kontrolne zbrojeve odabrane slike MD5, SHA-1, SHA-256 i SHA-512","Výpočet kontrolních součtů MD5, SHA-1, SHA-256 a SHA-512 vybraného obrazu","Beregn MD5, SHA-1, SHA-256 og SHA-512 checksums af det valgte billede","MD5, SHA-1, SHA-256 en SHA-512 controlesommen berekenen van de geselecteerde image","Laske MD5, SHA-1, SHA-256 ja SHA-512 tarkistussummia valitusta levykuvasta","Calculez les sommes de contrôle MD5, SHA-1, SHA-256 et SHA-512 de l'image sélectionnée","Berechnung von MD5-, SHA-1-, SHA-256- und SHA-512-Prüfsummen für das ausgewählte Bild","Υπολογίστε τα αθροίσματα ελέγχου MD5, SHA-1, SHA-256 και SHA-512 της επιλεγμένης εικόνας","חישוב סיכומי ביקורת מסוג MD5, SHA-1, SHA-256 ו־SHA-512 של קובץ התמונה שנבחרה","A kiválasztott képfájl MD5, SHA-1, SHA-256 és SHA-512 ellenőrző összegének kiszámítása","Hitung checksum MD5, SHA-1, SHA-256 dan SHA-512 dari image yang dipilih","Calcola i checksum MD5, SHA-1, SHA-256 e SHA-512 dell'immagine selezionata","選択されたイメージのMD5、SHA-1、SHA-256及びSHA-512チェックサムを計算します。","선택한 이미지의 MD5, SHA-1, SHA-256 및 SHA-512 체크섬 계산","Izskaitļo izvēlētā virtuālā attēla MD5, SHA-1, SHA-256 un SHA-512 kontrolsummas","Apskaičiuokite pasirinkto vaizdo MD5, SHA-1, SHA-256 ir SHA-512 kontrolines sumas","Kira MD5, SHA-1, SHA-256 dan SHA-512 checksum imej yang dipilih","Kalkuler MD5, SHA-1, SHA-256 og SHA-512 sjekksummer fra valgt speiling","MD5، SHA-1، SHA-256 و SHA-512 را برای تصویر انتخابی محاسبه کنید","Oblicz sumy kontrolne MD5, SHA-1, SHA-256 i SHA-512 dla wybranego obrazu","Calcular somas de verificação MD5, SHA-1, SHA-256 e SHA-512 da imagem selecionada","Calcular checksums MD5, SHA-1, SHA-256 e SHA-512 da imagem selecionada","Compută MD5, SHA-1, SHA-256 și SHA-512 suma de control ale imaginilor selectate","Вычислить контрольные суммы MD5, SHA-1, SHA-256 и SHA-512 выбранного образа","Izračunajte MD5, SHA-1, SHA-256 i SHA-512 kontrolne preglede izabrane slike","Vypočítajte kontrolné súčty vybratého obrazu (MD5, SHA-1, SHA-256 a SHA-512)","Račun MD5, SHA-1, SHA-256 in SHA-512 kontrolni vsoti izbrane slike","Calcule las sumas de comprobación MD5, SHA-1, SHA-256 y SHA-512 de la imagen seleccionada","Beräkna kontrollsummor MD5, SHA-1, SHA-256 och SHA-512 för den valda avbilden","คำนวนรหัส MD5, SHA-1, SHA-256, SHA-512 ของไฟล์อิมเมจที่เลือก","Seçilen yansının MD5, SHA-1, SHA-256 ve SHA-512 sağlama toplamlarını hesaplayın","Обчислення контрольних сум MD5, SHA-1, SHA-256 та SHA-512 для вибраних образів","Tính tổng kiểm MD5, SHA-1, SHA-256 và SHA-512 của tệp đã chọn"
"Feature11","710","Text","","Perform bad blocks checks, including detection of ""fake"" flash drives","إجراء فحوصات كتل تالفة ، بما في ذلك الكشف عن محركات أقراص فلاش ""زائفة\","Проверяване за лоши блокове, включително засичане на ""фалшиви"" устройства","执行坏块检查包括对”假“U盘的检测","執行壞軌檢查包括對”假“USB 快閃磁碟機的偵測","Izvršite provjere loših blokova, uključujući otkrivanje ""lažnih"" flash pogona","Provést kontrolu vadných bloků, včetně detekce ""falešných"" bloků. flash disky","Udøv dårlige blokke tjeks, inklusiv opdagelse af ""falske"" flashdrev","Controles uitvoeren op slechte blokken, inclusief detectie van ""valse"" flashdrives","Suorita viallisten lohkojen tarkistuksia, sisältäen ""valheellisten"" muistitikkujen tunnistamisen","Executez un test de mauvais secteurs avec detection des ""fake drives\","Durchführung von Prüfungen auf fehlerhafte Blöcke, einschließlich der Erkennung von ""gefälschten"" Flash-Laufwerken","Εκτελέστε ελέγχους εσφαλμένων block, συμπεριλαμβανομένου του εντοπισμού ""ψευδών"" μονάδων flash","ביצוע בדיקות אחר בלוקים (אזורים) פגומים, כולל זיהוי של כונני הבזק ""מזוייפים\","Hibás blokkok ellenőrzése, beleértve a ""hamis"" flash meghajtók detektálását","Lakukan cek Blok yang buruk, termasuk deteksi USB Flash Disk ""PALSU\","Esegui controlli dei blocchi danneggiati, incluso il rilevamento di unità flash ""false\","不良ブロックチェック及び容量詐欺ドライブの検知を行います。","""위조"" 플래시 드라이브 감지를 포함하여 불량 블록 검사 수행","Izpilda bojāto bloku pārbaudi ieskaitot ""falsificēto"" nesēju noteikšanu","Atlikite blogų blokų patikrinimus, įskaitant ""netikrų"" flash diskų aptikimą","Melakukan pemeriksaan blok buruk, termasuk pengesanan pemacu kilat ""palsu\","Utfør sjekk for dårlige sektorer, inkludert sjekk for forfalskede flash disker","بررسی بلوک های بد، از جمله تشخیص درایوهای فلش ""جعلی"" را انجام دهید","Sprawdź dysk pod względem spójności danych lub wykryj ""nieorginalny"" pendrive","Executar verificações de blocos defeituosos, incluindo detecção de unidades flash ""falsificadas\","Executar verificações de blocos inválidos, incluindo a detecção de unidades flash ""falsas\","Verifică blocuri rele, incluzând detectarea de drive-uri flash ""false\","Проверить наличие плохих блоков, обнаружить ""поддельные"" флешки","Izvršite provere loših blokova, uključujući otkrivanje ""lažnih"" fleš diskova","Vykonajte kontroly zlých blokov vrátane detekcie „falošných"" prenosných diskov","Izvajanje preverjanj slabih blokov, vključno z odkrivanjem »lažnih« bliskavic","Realice comprobaciones de bloques defectuosos, incluida la detección de unidades flash ""falsas\","Utför kontroll av trasiga block, inklusive upptäckt av ""falska"" USB-minnen","ดำเนินการตรวจสอบบล็อกข้อมูลที่พัง รวมไปถึงการทดสอบว่าเป็นแฟลชไดร์ฟ ""ปลอม"" หรือไม่","""Sahte"" flash sürücülerin tespiti de dahil olmak üzere hatalı blok kontrolleri gerçekleştirin","Перевірка дисків (включаючи фальшиві диски)","Thực hiện kiểm tra điểm lỗi, bao gồm phát hiện ổ đĩa ""giả\"
"Feature12","711","Text","","Download official Microsoft Windows retail ISOs","قم بتنزيل ملفات ISO الرسمية الخاصة بـ Microsoft Windows","Изтегляне на официални Microsoft Windows ISO образи","下载微软官方 Windows 镜像","下載微軟官方 Windows 映像檔","Preuzimanje službenih ISO-ova za maloprodaju sustava Microsoft Windows","Stažení oficiálních souborů ISO systému Microsoft Windows","Hent officielle Microsoft Windows detail ISOer","Officiële Microsoft Windows retail ISO's downloaden","Lataa virallisia Microsoft Windowsin jälleenmyyntiversion ISO-levykuvia","Téléchargez des images ISOs commerciales officielles de Microsoft Windows","Offizielle Microsoft Windows-ISOs herunterladen","Κατεβάστε τα επίσημα retail ISO των Microsoft Windows","הורדת קובצי ה־ISO הקמעונאיים הרשמיים של Microsoft Windows","Hivatalos Microsoft Windows kiskereskedelmi ISO képfájlok letöltése","Unduh ISO Microsoft Windows resmi","Scarica le ISO ufficiali di Microsoft Windows","マイクロソフト公式のWindows ISOをダウンロードします。","공식 Microsoft Windows 리테일 ISO 다운로드","Lejupielādē oficiālos Microsoft ISO failus","Atsisiųskite oficialius Microsoft Windows mažmeninės prekybos ISO","Muat turun rasmi ISO runcit Microsoft Windows","Last ned offisielle Windows ISOer","ISO های رسمی ماکروسافت را دریافت کنید","Pobierz oficjalny obraz ISO systemu Microsoft Windows","Baixar ISOs oficiais do Microsoft Windows","Transferir ISOs oficiais do Microsoft Windows Retail","Descarcă un Microsoft Windows ISO oficial de vânzare","Загрузить официальные ISO-образы Windows","Preuzmite zvanične Microsoft Windows maloprodajne ISO-ove","Stiahnite si oficiálne ISO pre Microsoft Windows","Prenos uradnih Microsoft Windows maloprodaja ISOs","Descargue los ISO oficiales de Microsoft Windows","Ladda ner officiella Microsoft Windows ISO-filer","ดาวน์โหลดอิมเมจไฟล์ของ Windows จากเว็บไซต์ทางการ","Resmi Microsoft Windows Retail ISO'larını indirin","Завантаження офіційних образів Microsoft Windows","Tải xuống các tệp Microsoft Windows ISO bán lẻ chính thức"
"Feature13","712","Text","","Download UEFI Shell ISOs","قم بتنزيل UEFI Shell ISOs","Изтегляне на UEFI Shell образи","下载 UEFI Shell 镜像","下載 UEFI Shell 映像檔","Preuzmite ISO-ove UEFI ljuske","Stažení souborů UEFI Shell ISO","Hent UEFI Shell ISOer","UEFI Shell ISO's downloaden","Lataa UEFI Shell ISO-levykuvia","Téléchargez des images ISOs du Shell UEFI","UEFI-Shell-ISOs herunterladen","Κατεβάστε τα ISO Shell UEFI","הורדת קובצי ISO של מעטפת UEFI","UEFI Shell ISO képfájlok letöltése","Unduh Shell ISO UEFI","Scarica le ISO della shell UEFI","UEFIシェルのISOをダウンロードします。","UEFI Shell ISO 다운로드","Lejupielādē UEFI OS ISO failus","Atsisiųskite UEFI Shell ISO","Muat turun ISO Shell UEFI","Last ned UEFI kommandolinje ISOer","ISO های پوسته UEFI را دانلود کنید","Ściągnij obrazy ISO UEFI Shell","Baixar ISOs do Shell UEFI","Transferir ISOs de UEFI Shell","Descarcă UEFI Shell ISO-uri","Загрузить ISO-образы оболочки UEFI","Preuzmite UEFI Shell ISOs","Stiahnite UEFI Shell ISO","Prenos UEFI Shell ISOs","Descargar ISO de UEFI Shell","Ladda ner UEFI-shell ISO-filer","ดาวน์โหลดอิมเมจไฟล์ของ UEFI Shell","UEFI Shell ISO'larını indirin","Завантаження командної оболонки UEFI ISO","Tải xuống các tệp UEFI Shell ISO"
"Feature14","713","Text","",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
"Feature15","714","Text","",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
"Feature16","715","Text","",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,

1 Field ID Type (Type) default en-us ar-sa bg-bg zh-cn zh-tw hr-hr cs-cz da-dk nl-nl fi-fi fr-fr de-de el-gr he-il hu-hu id-id it-it ja-jp ko-kr lv-lv lt-lt ms-my nb-no fa-ir pl-pl pt-br pt-pt ro-ro ru-ru sr-latn-rs sk-sk sl-si es-es sv-se th-th tr-tr uk-ua vi-vn
13 DesktopScreenshot2 101 Relative path (or URL to file in Partner Center) listing/en-us/Screenshot2.png
14 DesktopScreenshot3 102 Relative path (or URL to file in Partner Center) listing/en-us/Screenshot3.png
15 DesktopScreenshot4 103 Relative path (or URL to file in Partner Center) listing/en-us/Screenshot4.png
16 DesktopScreenshot5 104 Relative path (or URL to file in Partner Center)
17 DesktopScreenshot6 105 Relative path (or URL to file in Partner Center)
18 DesktopScreenshot7 106 Relative path (or URL to file in Partner Center)
19 DesktopScreenshot8 107 Relative path (or URL to file in Partner Center)
114 Feature9 708 Text Create VHD/DD images of the selected drive إنشاء صور VHD / DD لمحرك الأقراص المحدد Създаване на VHD/DD образи на избраното устройство 为选择的驱动器创建 VHD/DD 镜像 為選中的驅動創建 VHD/DD 鏡像 為選中的磁碟機建立 VHD/DD 映像檔 Stvaranje VHD/DD slika odabranog pogona Vytvoření obrazů VHD/DD z vybrané jednotky Lav VHD/DD billeder af det valgte drev VHD/DD-images van de geselecteerde schijf aanmaken Luo VHD/DD-kuvia valitusta asemasta Créez des images VHD/DD du périphérique sélectionné VHD/DD-Images des ausgewählten Laufwerks erstellen Δημιουργήστε εικόνες VHD/DD της επιλεγμένης μονάδας δίσκου יצירת קובצי תמונה מסוג VHD/DD של הכונן שנבחר VHD/DD képfájl készítése a kiválasztott meghajtóról Buat image VHD/DD dari penyimpanan yang dipilih Crea immagini VHD/DD dell'unità selezionata 選択されたドライブのVHD/DDイメージを作成します。 선택한 드라이브의 VHD/DD 이미지 만들기 Izveido izvēlētā diska VHD/DD virtuālos attēlus Sukurkite pasirinkto disko VHD / DD vaizdus Buat imej VHD/DD bagi pemacu yang dipilih Lag VHD/DD speilinger av valgt disk تصاویر VHD/DD از درایو انتخاب شده ایجاد کنید Stwórz obraz VHD/DD z wybranego dysku Criar imagens VHD/DD do dispositivo selecionado Criar imagens VHD/DD do dispositivo selecionado Crează imagini VHD/DD de pe drive-ul selectat Создать образы VHD/DD выбранного диска Kreiranje VHD/DD slika izabrane disk jedinice Vytvorte obrazy VHD/DD z vybratej jednotky Ustvarjanje VHD/DD slik izbranega pogona Cree imágenes VHD/DD de la unidad seleccionada Skapa VHD/DD-avbilder av den valda enheten สร้างอิมเมจไฟล์แบบ VHD/DD ของไดร์ฟที่เลือก Seçilen sürücünün VHD/DD yansılarını oluşturun Створення образів VHD/DD з вибраних дисків Tạo tệp VHD/DD từ ổ đĩa đã chọn
115 Feature10 709 Text Compute MD5, SHA-1, SHA-256 and SHA-512 checksums of the selected image حساب المجموع الاختباري MD5 و SHA-1 و SHA-256 و SHA-512 للصورة المحددة Изчисляване на MD5, SHA-1, SHA-256 и SHA-512 чексуми на избраният образ 计算被选择镜像的 MD5、SHA-1、SHA-256 和 SHA-512 校验码 計算被選中鏡像的 MD5、SHA-1、SHA-256 和 SHA-512 校驗碼 計算被選中映像的 MD5、SHA-1、SHA-256 和 SHA-512 檢查碼 Izračunajte kontrolne zbrojeve odabrane slike MD5, SHA-1, SHA-256 i SHA-512 Výpočet kontrolních součtů MD5, SHA-1, SHA-256 a SHA-512 vybraného obrazu Beregn MD5, SHA-1, SHA-256 og SHA-512 checksums af det valgte billede MD5, SHA-1, SHA-256 en SHA-512 controlesommen berekenen van de geselecteerde image Laske MD5, SHA-1, SHA-256 ja SHA-512 tarkistussummia valitusta levykuvasta Calculez les sommes de contrôle MD5, SHA-1, SHA-256 et SHA-512 de l'image sélectionnée Berechnung von MD5-, SHA-1-, SHA-256- und SHA-512-Prüfsummen für das ausgewählte Bild Υπολογίστε τα αθροίσματα ελέγχου MD5, SHA-1, SHA-256 και SHA-512 της επιλεγμένης εικόνας חישוב סיכומי ביקורת מסוג MD5,‏ SHA-1,‏ SHA-256 ו־SHA-512 של קובץ התמונה שנבחרה A kiválasztott képfájl MD5, SHA-1, SHA-256 és SHA-512 ellenőrző összegének kiszámítása Hitung checksum MD5, SHA-1, SHA-256 dan SHA-512 dari image yang dipilih Calcola i checksum MD5, SHA-1, SHA-256 e SHA-512 dell'immagine selezionata 選択されたイメージのMD5、SHA-1、SHA-256及びSHA-512チェックサムを計算します。 선택한 이미지의 MD5, SHA-1, SHA-256 및 SHA-512 체크섬 계산 Izskaitļo izvēlētā virtuālā attēla MD5, SHA-1, SHA-256 un SHA-512 kontrolsummas Apskaičiuokite pasirinkto vaizdo MD5, SHA-1, SHA-256 ir SHA-512 kontrolines sumas Kira MD5, SHA-1, SHA-256 dan SHA-512 checksum imej yang dipilih Kalkuler MD5, SHA-1, SHA-256 og SHA-512 sjekksummer fra valgt speiling MD5، SHA-1، SHA-256 و SHA-512 را برای تصویر انتخابی محاسبه کنید Oblicz sumy kontrolne MD5, SHA-1, SHA-256 i SHA-512 dla wybranego obrazu Calcular somas de verificação MD5, SHA-1, SHA-256 e SHA-512 da imagem selecionada Calcular checksums MD5, SHA-1, SHA-256 e SHA-512 da imagem selecionada Compută MD5, SHA-1, SHA-256 și SHA-512 suma de control ale imaginilor selectate Вычислить контрольные суммы MD5, SHA-1, SHA-256 и SHA-512 выбранного образа Izračunajte MD5, SHA-1, SHA-256 i SHA-512 kontrolne preglede izabrane slike Vypočítajte kontrolné súčty vybratého obrazu (MD5, SHA-1, SHA-256 a SHA-512) Račun MD5, SHA-1, SHA-256 in SHA-512 kontrolni vsoti izbrane slike Calcule las sumas de comprobación MD5, SHA-1, SHA-256 y SHA-512 de la imagen seleccionada Beräkna kontrollsummor MD5, SHA-1, SHA-256 och SHA-512 för den valda avbilden คำนวนรหัส MD5, SHA-1, SHA-256, SHA-512 ของไฟล์อิมเมจที่เลือก Seçilen yansının MD5, SHA-1, SHA-256 ve SHA-512 sağlama toplamlarını hesaplayın Обчислення контрольних сум MD5, SHA-1, SHA-256 та SHA-512 для вибраних образів Tính tổng kiểm MD5, SHA-1, SHA-256 và SHA-512 của tệp đã chọn
116 Feature11 710 Text Perform bad blocks checks, including detection of "fake" flash drives إجراء فحوصات كتل تالفة ، بما في ذلك الكشف عن محركات أقراص فلاش "زائفة\ Проверяване за лоши блокове, включително засичане на "фалшиви" устройства 执行坏块检查,包括对”假“U盘的检测 執行壞塊檢查,包括對”假“USB 快閃磁碟機的檢測 執行壞軌檢查,包括對”假“USB 快閃磁碟機的偵測 Izvršite provjere loših blokova, uključujući otkrivanje "lažnih" flash pogona Provést kontrolu vadných bloků, včetně detekce "falešných" bloků. flash disky Udøv dårlige blokke tjeks, inklusiv opdagelse af "falske" flashdrev Controles uitvoeren op slechte blokken, inclusief detectie van "valse" flashdrives Suorita viallisten lohkojen tarkistuksia, sisältäen "valheellisten" muistitikkujen tunnistamisen Executez un test de mauvais secteurs avec detection des "fake drives\ Durchführung von Prüfungen auf fehlerhafte Blöcke, einschließlich der Erkennung von "gefälschten" Flash-Laufwerken Εκτελέστε ελέγχους εσφαλμένων block, συμπεριλαμβανομένου του εντοπισμού "ψευδών" μονάδων flash ביצוע בדיקות אחר בלוקים (אזורים) פגומים, כולל זיהוי של כונני הבזק "מזוייפים\ Hibás blokkok ellenőrzése, beleértve a "hamis" flash meghajtók detektálását Lakukan cek Blok yang buruk, termasuk deteksi USB Flash Disk "PALSU\ Esegui controlli dei blocchi danneggiati, incluso il rilevamento di unità flash "false\ 不良ブロックチェック及び容量詐欺ドライブの検知を行います。 "위조" 플래시 드라이브 감지를 포함하여 불량 블록 검사 수행 Izpilda bojāto bloku pārbaudi ieskaitot "falsificēto" nesēju noteikšanu Atlikite blogų blokų patikrinimus, įskaitant "netikrų" flash diskų aptikimą Melakukan pemeriksaan blok buruk, termasuk pengesanan pemacu kilat "palsu\ Utfør sjekk for dårlige sektorer, inkludert sjekk for forfalskede flash disker بررسی بلوک های بد، از جمله تشخیص درایوهای فلش "جعلی" را انجام دهید Sprawdź dysk pod względem spójności danych lub wykryj "nieorginalny" pendrive Executar verificações de blocos defeituosos, incluindo detecção de unidades flash "falsificadas\ Executar verificações de blocos inválidos, incluindo a detecção de unidades flash "falsas\ Verifică blocuri rele, incluzând detectarea de drive-uri flash "false\ Проверить наличие плохих блоков, обнаружить "поддельные" флешки Izvršite provere loših blokova, uključujući otkrivanje "lažnih" fleš diskova Vykonajte kontroly zlých blokov vrátane detekcie „falošných" prenosných diskov Izvajanje preverjanj slabih blokov, vključno z odkrivanjem »lažnih« bliskavic Realice comprobaciones de bloques defectuosos, incluida la detección de unidades flash "falsas\ Utför kontroll av trasiga block, inklusive upptäckt av "falska" USB-minnen ดำเนินการตรวจสอบบล็อกข้อมูลที่พัง รวมไปถึงการทดสอบว่าเป็นแฟลชไดร์ฟ "ปลอม" หรือไม่ "Sahte" flash sürücülerin tespiti de dahil olmak üzere hatalı blok kontrolleri gerçekleştirin Перевірка дисків (включаючи фальшиві диски) Thực hiện kiểm tra điểm lỗi, bao gồm phát hiện ổ đĩa "giả\
117 Feature12 711 Text Download official Microsoft Windows retail ISOs قم بتنزيل ملفات ISO الرسمية الخاصة بـ Microsoft Windows Изтегляне на официални Microsoft Windows ISO образи 下载微软官方 Windows 镜像 下載微軟官方 Windows 鏡像 下載微軟官方 Windows 映像檔 Preuzimanje službenih ISO-ova za maloprodaju sustava Microsoft Windows Stažení oficiálních souborů ISO systému Microsoft Windows Hent officielle Microsoft Windows detail ISOer Officiële Microsoft Windows retail ISO's downloaden Lataa virallisia Microsoft Windowsin jälleenmyyntiversion ISO-levykuvia Téléchargez des images ISOs commerciales officielles de Microsoft Windows Offizielle Microsoft Windows-ISOs herunterladen Κατεβάστε τα επίσημα retail ISO των Microsoft Windows הורדת קובצי ה־ISO הקמעונאיים הרשמיים של Microsoft Windows Hivatalos Microsoft Windows kiskereskedelmi ISO képfájlok letöltése Unduh ISO Microsoft Windows resmi Scarica le ISO ufficiali di Microsoft Windows マイクロソフト公式のWindows ISOをダウンロードします。 공식 Microsoft Windows 리테일 ISO 다운로드 Lejupielādē oficiālos Microsoft ISO failus Atsisiųskite oficialius Microsoft Windows mažmeninės prekybos ISO Muat turun rasmi ISO runcit Microsoft Windows Last ned offisielle Windows ISOer ISO های رسمی ماکروسافت را دریافت کنید Pobierz oficjalny obraz ISO systemu Microsoft Windows Baixar ISOs oficiais do Microsoft Windows Transferir ISOs oficiais do Microsoft Windows Retail Descarcă un Microsoft Windows ISO oficial de vânzare Загрузить официальные ISO-образы Windows Preuzmite zvanične Microsoft Windows maloprodajne ISO-ove Stiahnite si oficiálne ISO pre Microsoft Windows Prenos uradnih Microsoft Windows maloprodaja ISOs Descargue los ISO oficiales de Microsoft Windows Ladda ner officiella Microsoft Windows ISO-filer ดาวน์โหลดอิมเมจไฟล์ของ Windows จากเว็บไซต์ทางการ Resmi Microsoft Windows Retail ISO'larını indirin Завантаження офіційних образів Microsoft Windows Tải xuống các tệp Microsoft Windows ISO bán lẻ chính thức
118 Feature13 712 Text Download UEFI Shell ISOs قم بتنزيل UEFI Shell ISOs Изтегляне на UEFI Shell образи 下载 UEFI Shell 镜像 下載 UEFI Shell 鏡像 下載 UEFI Shell 映像檔 Preuzmite ISO-ove UEFI ljuske Stažení souborů UEFI Shell ISO Hent UEFI Shell ISOer UEFI Shell ISO's downloaden Lataa UEFI Shell ISO-levykuvia Téléchargez des images ISOs du Shell UEFI UEFI-Shell-ISOs herunterladen Κατεβάστε τα ISO Shell UEFI הורדת קובצי ISO של מעטפת UEFI UEFI Shell ISO képfájlok letöltése Unduh Shell ISO UEFI Scarica le ISO della shell UEFI UEFIシェルのISOをダウンロードします。 UEFI Shell ISO 다운로드 Lejupielādē UEFI OS ISO failus Atsisiųskite UEFI Shell ISO Muat turun ISO Shell UEFI Last ned UEFI kommandolinje ISOer ISO های پوسته UEFI را دانلود کنید Ściągnij obrazy ISO UEFI Shell Baixar ISOs do Shell UEFI Transferir ISOs de UEFI Shell Descarcă UEFI Shell ISO-uri Загрузить ISO-образы оболочки UEFI Preuzmite UEFI Shell ISOs Stiahnite UEFI Shell ISO Prenos UEFI Shell ISOs Descargar ISO de UEFI Shell Ladda ner UEFI-shell ISO-filer ดาวน์โหลดอิมเมจไฟล์ของ UEFI Shell UEFI Shell ISO'larını indirin Завантаження командної оболонки UEFI ISO Tải xuống các tệp UEFI Shell ISO
119 Feature14 713 Text
120 Feature15 714 Text
121 Feature16 715 Text
122 Feature17 716 Text
123 Feature18 717 Text
124 Feature17 Feature19 716 718 Text
125 Feature18 Feature20 717 719 Text
126 Feature19 MinimumHardwareReq1 718 800 Text
127 Feature20 MinimumHardwareReq2 719 801 Text
128 MinimumHardwareReq1 MinimumHardwareReq3 800 802 Text
129 MinimumHardwareReq2 MinimumHardwareReq4 801 803 Text
130 MinimumHardwareReq3 MinimumHardwareReq5 802 804 Text
131 MinimumHardwareReq4 MinimumHardwareReq6 803 805 Text
132 MinimumHardwareReq5 MinimumHardwareReq7 804 806 Text
133 MinimumHardwareReq6 MinimumHardwareReq8 805 807 Text
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279

View File

@ -3,6 +3,9 @@
@echo off
setlocal EnableExtensions DisableDelayedExpansion
rem if set, this will override the version for the package
rem set VERSION_OVERRIDE=4.4.2104.0
goto main
:ReplaceTokenInFile
@ -66,13 +69,31 @@ for %%a in (%ARCHS%) do (
)
)
rem exiftool.exe can't be installed in the Windows system directories...
if not exist exiftool.exe (
echo exiftool.exe must exist in this directory
goto out
)
rem Make sure we're not trying to create a package from an ALPHA or BETA version!
exiftool -s3 -*InternalName* rufus_x64.exe | findstr /C:"ALPHA" 1>nul && (
echo Alpha version detected - ABORTED
goto out
)
exiftool -s3 -*InternalName* rufus_x64.exe | findstr /C:"BETA" 1>nul && (
echo Beta version detected - ABORTED
goto out
)
rem Populate the version from the executable
set target=%~dp0rufus_x64.exe
set target=%target:\=\\%
wmic datafile where "name='%target%'" get version | find /v "Version" > version.txt
set /p VERSION=<version.txt
set VERSION=%VERSION: =%
del version.txt
if "%VERSION_OVERRIDE%"=="" (
exiftool -s3 -*FileVersionNumber* rufus_x64.exe > version.txt
set /p VERSION=<version.txt
del version.txt
) else (
echo WARNING: Forcing version to %VERSION_OVERRIDE%
set VERSION=%VERSION_OVERRIDE%
)
echo Will create %VERSION% AppStore Bundle
pause

View File

@ -7,6 +7,14 @@ Or simply download https://files.akeo.ie/pollock/pollock-1.5.exe and follow its
o v4.?? (202?.??.??)
- *NEW* MSG_337 "An additional file ('diskcopy.dll') must be downloaded from Microsoft to install MS-DOS (...)"
- *NEW* MSG_338 "Revoked UEFI bootloader detected"
- *NEW* MSG_339 "Rufus detected that the ISO you have selected contains a UEFI bootloader that has been revoked (...)"
- *NEW* MSG_340 "a \"Security Violation\" screen"
- *NEW* MSG_341 "a Windows Recovery Screen (BSOD) with '%s'"
- *NEW MSG_342 "Compressed VHDX Image"
- *NEW* MSG_343 "Uncompressed VHD Image"
- *NEW* MSG_344 "Full Flash Update Image"
- *NEW* MSG_345 "Some additional data must be downloaded from Microsoft to use this functionality (...)"
o v3.22 (2023.??.??)
// MSG_144 is aimed the the ISO download feature

View File

@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: 3.22\n"
"Report-Msgid-Bugs-To: pete@akeo.ie\n"
"POT-Creation-Date: 2023-05-26 12:25+0100\n"
"PO-Revision-Date: 2023-05-26 12:25+0100\n"
"POT-Creation-Date: 2023-07-10 11:13+0200\n"
"PO-Revision-Date: 2023-07-10 11:25+0200\n"
"Last-Translator: \n"
"Language-Team: \n"
"Language: fr_FR\n"
@ -13,7 +13,7 @@ msgstr ""
"X-Poedit-SourceCharset: UTF-8\n"
"X-Rufus-LanguageName: French (Français)\n"
"X-Rufus-LCID: 0x040c, 0x080c, 0x0c0c, 0x100c, 0x140c, 0x180c, 0x1c0c, 0x200c, 0x240c, 0x280c, 0x2c0c, 0x300c, 0x340c, 0x380c, 0xe40c\n"
"X-Generator: Poedit 3.3.1\n"
"X-Generator: Poedit 3.3.2\n"
#. • IDD_DIALOG → IDS_DRIVE_PROPERTIES_TXT
msgid "Drive Properties"
@ -1090,7 +1090,7 @@ msgid "Version %d.%d (Build %d)"
msgstr ""
#. • MSG_176
msgid "English translation: Pete Batard <mailto:pete@akeo.ie>"
msgid "mailto:support@akeo.ie"
msgstr "Traduction Française : Pete Batard <mailto:pete@akeo.ie>"
#. • MSG_177
@ -1862,6 +1862,52 @@ msgstr ""
"\n"
"Note : Ce fichier sera téléchargé dans le répertoire de l'application et réutilisé automatiquement s'il est présent."
#. • MSG_338
msgid "Revoked UEFI bootloader detected"
msgstr "Bootloader UEFI révoqué détecté"
#. • MSG_339
msgid ""
"Rufus detected that the ISO you have selected contains a UEFI bootloader that has been revoked and that will produce %s, when Secure Boot is enabled on a fully up to date UEFI system.\n"
"\n"
"- If you obtained this ISO image from a non reputable source, you should consider the possibility that it might contain UEFI malware and avoid booting from it.\n"
"- If you obtained it from a trusted source, you should try to locate a more up to date version, that will not produce this warning."
msgstr ""
"Rufus a détecté que lISO que vous avez sélectionnée contient un bootloader UEFI révoqué, qui devrait produire %s sur un système UEFI à jour, lorsque 'Secure Boot' est activé.\n"
"\n"
"- Si vous avez obtenu cette image ISO à partir dune source douteuse, vous devriez envisager la possibilité quelle puisse contenir un logiciel malveillant, et éviter de démarrer à partir de celle-ci.\n"
"- Si vous lavez obtenu à partir dune source fiable, vous devriez essayer de trouver une version plus récente, où cette notification ne se produit pas."
#. • MSG_340
msgid "a \"Security Violation\" screen"
msgstr "un écran « Violation de sécurité »"
#. • MSG_341
msgid "a Windows Recovery Screen (BSOD) with '%s'"
msgstr "un écran de récupération Windows (BSOD) avec '%s'"
#. • MSG_342
msgid "Compressed VHDX Image"
msgstr "Image VHDX compressée"
#. • MSG_343
msgid "Uncompressed VHD Image"
msgstr "Image VHD non compressée"
#. • MSG_344
msgid "Full Flash Update Image"
msgstr "Image 'Full Flash Update'"
#. • MSG_345
msgid ""
"Some additional data must be downloaded from Microsoft to use this functionality:\n"
"- Select 'Yes' to connect to the Internet and download it\n"
"- Select 'No' to cancel the operation"
msgstr ""
"Des données complémentaires doivent être téléchargées à partir du site Microsoft avant d'utiliser cette fonctionnalité :\n"
"- Sélectionnez 'Oui' pour vous connecter à Internet et le télécharger ces données\n"
"- Sélectionnez 'Non' pour annuler lopération"
#. • MSG_900
#.
#. The following messages are for the Windows Store listing only and are not used by the application

View File

@ -3,7 +3,7 @@ msgstr ""
"Project-Id-Version: 3.22\n"
"Report-Msgid-Bugs-To: pete@akeo.ie\n"
"POT-Creation-Date: 2023-04-17 13:44+0100\n"
"PO-Revision-Date: 2023-04-17 13:46+0100\n"
"PO-Revision-Date: 2024-01-10 12:20+0000\n"
"Last-Translator: \n"
"Language-Team: \n"
"Language: nb_NO\n"
@ -13,7 +13,7 @@ msgstr ""
"X-Poedit-SourceCharset: UTF-8\n"
"X-Rufus-LanguageName: Norwegian (Norsk)\n"
"X-Rufus-LCID: 0x0414\n"
"X-Generator: Poedit 3.2.2\n"
"X-Generator: Poedit 3.4.2\n"
#. • IDD_DIALOG → IDS_DRIVE_PROPERTIES_TXT
msgid "Drive Properties"
@ -803,7 +803,7 @@ msgstr ""
#. • MSG_117
msgid "Standard Windows installation"
msgstr "Standard Windows instalasjon"
msgstr "Standard Windows installasjon"
#. • MSG_118
#.
@ -1839,7 +1839,7 @@ msgstr "Ikke gi Windows To Go tilgang til interne harddisker"
#. • MSG_333
msgid "Create a local account with username:"
msgstr "Lag en lokal brukerkongot med med brukernavnet:"
msgstr "Lag en lokal brukerkonto med brukernavnet:"
#. • MSG_334
msgid "Set regional options to the same values as this user's"

View File

@ -1802,43 +1802,43 @@ msgstr "無法開啟或讀取 '%s'"
#. • MSG_325
msgid "Applying Windows customization: %s"
msgstr "正在應用 Windows 自定義設置%s"
msgstr "正在套用 Windows 客製化設定%s"
#. • MSG_326
msgid "Applying user options..."
msgstr "正在應用用戶設置..."
msgstr "正在套用使用者設定..."
#. • MSG_327
msgid "Windows User Experience"
msgstr "Windows 用戶體驗"
msgstr "Windows 使用者體驗"
#. • MSG_328
msgid "Customize Windows installation?"
msgstr "自定義 Windows 安裝?"
msgstr "客製化 Windows 安裝?"
#. • MSG_329
msgid "Remove requirement for 4GB+ RAM, Secure Boot and TPM 2.0"
msgstr "移除對 4GB+ 內存、安全引導和 TPM 2.0 的要求"
msgstr "移除對 4GB+ 記憶體、安全開機和 TPM 2.0 的要求"
#. • MSG_330
msgid "Remove requirement for an online Microsoft account"
msgstr "移除對登錄微軟賬戶的要求"
msgstr "將登入微軟帳號的要求移除"
#. • MSG_331
msgid "Disable data collection (Skip privacy questions)"
msgstr "關閉數據收集 (跳過隱私設置)"
msgstr "關閉資料收集 (跳過隱私設定)"
#. • MSG_332
msgid "Prevent Windows To Go from accessing internal disks"
msgstr "阻止 Windows To Go 訪問內部磁盤"
msgstr "防止 Windows To Go 存取內部磁碟"
#. • MSG_333
msgid "Create a local account with username:"
msgstr "創建一個使用此用戶名的本地賬號:"
msgstr "使用此使用者名建立一個本機帳戶:"
#. • MSG_334
msgid "Set regional options to the same values as this user's"
msgstr "使用當前用戶的區域設置"
msgstr "使用目前用戶的區域設定"
#. • MSG_335
msgid "Disable BitLocker automatic device encryption"
@ -1860,7 +1860,7 @@ msgstr "官方網站: %s"
#. • MSG_902
msgid "Source Code: %s"
msgstr "源碼: %s"
msgstr "源碼: %s"
#. • MSG_903
msgid "ChangeLog: %s"
@ -1887,52 +1887,52 @@ msgstr "啟動"
#.
#. This and subsequent messages will be listed in the 'Features' section of the Windows Store page
msgid "Format USB, flash card and virtual drives to FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3"
msgstr "將 U 盤、存儲卡或虛擬驅動器格式化為 FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3 格式"
msgstr "將隨身碟、記憶卡或虛擬光碟機格式化為 FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3 格式"
#. • MSG_911
msgid "Create FreeDOS bootable USB drives"
msgstr "創建 FreeDOS 可啟動驅動器"
msgstr "建立 FreeDOS 可啟隨身碟"
#. • MSG_912
msgid "Create bootable drives from bootable ISOs (Windows, Linux, etc.)"
msgstr "從可啟動 ISO 文件 (Windows 和 Linux 等) 創建可啟動驅動器"
msgstr "從可啟動 ISO 檔案 (Windows 和 Linux 等) 建立可啟動隨身碟"
#. • MSG_913
msgid "Create bootable drives from bootable disk images, including compressed ones"
msgstr "從可啟動硬盤鏡像 (包括壓縮鏡像) 創建可啟動驅動器"
msgstr "從可啟動硬碟映像檔 (包括壓縮映像檔) 建立可啟動隨身碟"
#. • MSG_914
msgid "Create BIOS or UEFI bootable drives, including UEFI bootable NTFS"
msgstr "創建 BIOS 或 UEFI 可啟動驅動器,包括 UEFI 可啟動的 NTFS 驅動器"
msgstr "建立 BIOS 或 UEFI 可啟動隨身碟,包括 UEFI 可啟動的 NTFS 隨身碟"
#. • MSG_915
msgid "Create 'Windows To Go' drives"
msgstr "創建 'Windows To Go' 驅動"
msgstr "建立 'Windows To Go' 隨身碟"
#. • MSG_916
msgid "Create Windows 11 installation drives for PCs that don't have TPM or Secure Boot"
msgstr "為沒有 TPM 或安全啟動功能的電腦創建 Windows 11 安裝驅動"
msgstr "為沒有 TPM 或安全開機功能的電腦建立 Windows 11 安裝隨身碟"
#. • MSG_917
msgid "Create persistent Linux partitions"
msgstr "創建持久 Linux 分區"
msgstr "建立持續性 Linux 磁區"
#. • MSG_918
msgid "Create VHD/DD images of the selected drive"
msgstr "為選中的驅動創建 VHD/DD 鏡像"
msgstr "為選中的磁碟機建立 VHD/DD 映像檔"
#. • MSG_919
msgid "Compute MD5, SHA-1, SHA-256 and SHA-512 checksums of the selected image"
msgstr "計算被選中鏡像的 MD5、SHA-1、SHA-256 和 SHA-512 校驗碼"
msgstr "計算被選中映像的 MD5、SHA-1、SHA-256 和 SHA-512 檢查碼"
#. • MSG_920
msgid "Perform bad blocks checks, including detection of \"fake\" flash drives"
msgstr "執行壞塊檢查包括對”假“USB 快閃磁碟機的檢測"
msgstr "執行壞軌檢查包括對”假“USB 快閃磁碟機的偵測"
#. • MSG_921
msgid "Download official Microsoft Windows retail ISOs"
msgstr "下載微軟官方 Windows 鏡像"
msgstr "下載微軟官方 Windows 映像檔"
#. • MSG_922
msgid "Download UEFI Shell ISOs"
msgstr "下載 UEFI Shell 鏡像"
msgstr "下載 UEFI Shell 映像檔"

View File

@ -605,6 +605,12 @@ t MSG_340 "a \"Security Violation\" screen"
t MSG_341 "a Windows Recovery Screen (BSOD) with '%s'"
t MSG_342 "Compressed VHDX Image"
t MSG_343 "Uncompressed VHD Image"
t MSG_344 "Full Flash Update Image"
t MSG_345 "Some additional data must be downloaded from Microsoft to use this functionality:\n"
"- Select 'Yes' to connect to the Internet and download it\n"
"- Select 'No' to cancel the operation"
t MSG_346 "Restrict Windows to S-Mode (INCOMPATIBLE with online account bypass)"
t MSG_347 "Expert Mode"
# The following messages are for the Windows Store listing only and are not used by the application
t MSG_900 "Rufus is a utility that helps format and create bootable USB flash drives, such as USB keys/pendrives, memory sticks, etc."
t MSG_901 "Official site: %s"
@ -2252,37 +2258,37 @@ t MSG_319 "忽略 Boot Marker"
t MSG_320 "正在重新整理磁區分割 (%s)..."
t MSG_321 "你選擇的映像檔是 ISOHybrid但是檔案作者沒有使之與 ISO/檔案複製模式相容。\n因此強制使用 DD 映像寫入模式。"
t MSG_322 "無法開啟或讀取 '%s'"
t MSG_325 "正在應用 Windows 自定義設置%s"
t MSG_326 "正在應用用戶設置..."
t MSG_327 "Windows 用戶體驗"
t MSG_328 "自定義 Windows 安裝?"
t MSG_329 "移除對 4GB+ 內存、安全引導和 TPM 2.0 的要求"
t MSG_330 "移除對登錄微軟賬戶的要求"
t MSG_331 "關閉數據收集 (跳過隱私設置)"
t MSG_332 "阻止 Windows To Go 訪問內部磁盤"
t MSG_333 "創建一個使用此用戶名的本地賬號:"
t MSG_334 "使用當前用戶的區域設置"
t MSG_325 "正在套用 Windows 客製化設定%s"
t MSG_326 "正在套用使用者設定..."
t MSG_327 "Windows 使用者體驗"
t MSG_328 "客製化 Windows 安裝?"
t MSG_329 "移除對 4GB+ 記憶體、安全開機和 TPM 2.0 的要求"
t MSG_330 "將登入微軟帳號的要求移除"
t MSG_331 "關閉資料收集 (跳過隱私設定)"
t MSG_332 "防止 Windows To Go 存取內部磁碟"
t MSG_333 "使用此使用者名建立一個本機帳戶:"
t MSG_334 "使用目前用戶的區域設定"
t MSG_335 "關閉 BitLocker 自動設備加密"
t MSG_336 "持久化日誌"
t MSG_900 "Rufus 是個能格式化並製作可開機 USB 快閃磁碟機USB 隨身碟、Memory Stick 等等)的工具。"
t MSG_901 "官方網站: %s"
t MSG_902 "源碼: %s"
t MSG_902 "源碼: %s"
t MSG_903 "更新日誌: %s"
t MSG_904 "本應用採用 GNU 通用公共許可證 (GPL) 第三版。\n具體許可證見 https://www.gnu.org/licenses/gpl-3.0.zh-tw.html。"
t MSG_905 "啟動"
t MSG_910 "將 U 盤、存儲卡或虛擬驅動器格式化為 FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3 格式"
t MSG_911 "創建 FreeDOS 可啟動驅動器"
t MSG_912 "從可啟動 ISO 文件 (Windows 和 Linux 等) 創建可啟動驅動器"
t MSG_913 "從可啟動硬盤鏡像 (包括壓縮鏡像) 創建可啟動驅動器"
t MSG_914 "創建 BIOS 或 UEFI 可啟動驅動器,包括 UEFI 可啟動的 NTFS 驅動器"
t MSG_915 "創建 'Windows To Go' 驅動"
t MSG_916 "為沒有 TPM 或安全啟動功能的電腦創建 Windows 11 安裝驅動"
t MSG_917 "創建持久 Linux 分區"
t MSG_918 "為選中的驅動創建 VHD/DD 鏡像"
t MSG_919 "計算被選中鏡像的 MD5、SHA-1、SHA-256 和 SHA-512 校驗碼"
t MSG_920 "執行壞塊檢查包括對”假“USB 快閃磁碟機的檢測"
t MSG_921 "下載微軟官方 Windows 鏡像"
t MSG_922 "下載 UEFI Shell 鏡像"
t MSG_910 "將隨身碟、記憶卡或虛擬光碟機格式化為 FAT/FAT32/NTFS/UDF/exFAT/ReFS/ext2/ext3 格式"
t MSG_911 "建立 FreeDOS 可啟隨身碟"
t MSG_912 "從可啟動 ISO 檔案 (Windows 和 Linux 等) 建立可啟動隨身碟"
t MSG_913 "從可啟動硬碟映像檔 (包括壓縮映像檔) 建立可啟動隨身碟"
t MSG_914 "建立 BIOS 或 UEFI 可啟動隨身碟,包括 UEFI 可啟動的 NTFS 隨身碟"
t MSG_915 "建立 'Windows To Go' 隨身碟"
t MSG_916 "為沒有 TPM 或安全開機功能的電腦建立 Windows 11 安裝隨身碟"
t MSG_917 "建立持續性 Linux 磁區"
t MSG_918 "為選中的磁碟機建立 VHD/DD 映像檔"
t MSG_919 "計算被選中映像的 MD5、SHA-1、SHA-256 和 SHA-512 檢查碼"
t MSG_920 "執行壞軌檢查包括對”假“USB 快閃磁碟機的偵測"
t MSG_921 "下載微軟官方 Windows 映像檔"
t MSG_922 "下載 UEFI Shell 映像檔"
#########################################################################
l "hr-HR" "Croatian (Hrvatski)" 0x041a, 0x081a, 0x101a
@ -4694,6 +4700,14 @@ t MSG_334 "Définir les options régionales avec les mêmes valeurs que celles d
t MSG_335 "Désactiver l'encryption automatique BitLocker"
t MSG_336 "Log persistent"
t MSG_337 "Un fichier supplémentaire ('diskcopy.dll') doit être téléchargé depuis Microsoft pour installer MS-DOS :\n- Sélectionnez 'Oui' pour vous connecter à Internet et le télécharger\n- Sélectionnez 'Non' pour annuler lopération\n\nNote : Ce fichier sera téléchargé dans le répertoire de l'application et réutilisé automatiquement s'il est présent."
t MSG_338 "Bootloader UEFI révoqué détecté"
t MSG_339 "Rufus a détecté que lISO que vous avez sélectionnée contient un bootloader UEFI révoqué, qui devrait produire %s sur un système UEFI à jour, lorsque 'Secure Boot' est activé.\n\n- Si vous avez obtenu cette image ISO à partir dune source douteuse, vous devriez envisager la possibilité quelle puisse contenir un logiciel malveillant, et éviter de démarrer à partir de celle-ci.\n- Si vous lavez obtenu à partir dune source fiable, vous devriez essayer de trouver une version plus récente, où cette notification ne se produit pas."
t MSG_340 "un écran « Violation de sécurité »"
t MSG_341 "un écran de récupération Windows (BSOD) avec '%s'"
t MSG_342 "Image VHDX compressée"
t MSG_343 "Image VHD non compressée"
t MSG_344 "Image 'Full Flash Update'"
t MSG_345 "Des données complémentaires doivent être téléchargées à partir du site Microsoft avant d'utiliser cette fonctionnalité :\n- Sélectionnez 'Oui' pour vous connecter à Internet et le télécharger ces données\n- Sélectionnez 'Non' pour annuler lopération"
t MSG_900 "Rufus est un utilitaire permettant de formater et de créer des média USB amorçables, tels que clés USB, mémoire flash, etc."
t MSG_901 "Site officiel : %s"
t MSG_902 "Code source: %s"
@ -9351,7 +9365,7 @@ t MSG_113 "Stort UDF-volum"
t MSG_114 "Dette bildet bruker Syslinux %s%s men dette programmet inkluderer kun installsjonsfiler for Syslinux %s%s.\n\nNye versjoner av Syslinux er ikke kompatible med hverandre, og dermed ikke mulig for Rufus å inkludere alle, 2 ekstra filer må lastes ned fra Internett ('ldlinux.sys' og 'ldlinux.bss'):\n- Velg 'Ja' For å koble til internett og laste ned disse filene\n- Velg 'Nei' for å avbryte\n\nOBS: Filene vil bli lastet ned i det aktuelle programmets mappe og vil bli brukt automatisk hvis de er tilstede."
t MSG_115 "Nedlasting påkrevd"
t MSG_116 "Dette bildet bruker Grub %s, men programmet inkluderer kun installasjonsfiler forGrub %s.\n\nForskjellige versjoner av Grub er muligens ikke kompatible med hverandre, og er ikke mulig å inkludere dem alle, Rufus vil prøve å finne en versjon av Grub installasjonfilen ('core.img') som passer til ditt bilde:\n- Velg 'Ja' for å koble til internett og forsøke å laste den ned\n- Velg 'Nei' for å bruke den innebygde versjonen uansett\n- Velg 'Avbryt' for å avbryte\n\nOBS: Filen vil bli lastet ned i den aktuelle program-mappen og vil bli brukt automatisk hvis tilgjengelig. Hvis ingen treff kan bli funnet, den innebygde versjonen vil bli brukt."
t MSG_117 "Standard Windows instalasjon"
t MSG_117 "Standard Windows installasjon"
t MSG_119 "avanserte stasjonsegenskaper"
t MSG_120 "avanserte formatalternativer"
t MSG_121 "Vis %s"
@ -9561,7 +9575,7 @@ t MSG_329 "Fjern krav om 4GB+ RAM, Secure Boot og TPM 2.0"
t MSG_330 "Fjern krav om en Microsoft konto"
t MSG_331 "Slå av all datainnsamling (hopp over spørsmålene)"
t MSG_332 "Ikke gi Windows To Go tilgang til interne harddisker"
t MSG_333 "Lag en lokal brukerkongot med med brukernavnet:"
t MSG_333 "Lag en lokal brukerkonto med brukernavnet:"
t MSG_334 "Sett regionale instillinger til det samme som den aktive brukerkontoen"
t MSG_335 "Deaktiver BitLocker kryptering av enheten"
t MSG_336 "Behold log"

View File

@ -7,7 +7,7 @@ This image, which can be mounted as a FAT file system or opened in 7-zip,
contains the following data:
o Secure Boot signed NTFS UEFI drivers, derived from ntfs-3g [1].
These drivers are the exact same as the read-only binaries from release 1.6,
These drivers are the exact same as the read-only binaries from release 1.7,
except for the addition of Microsoft's Secure Boot signature.
Note that, per Microsoft's current Secure Boot signing policies, the 32-bit
ARM driver (ntfs_arm.efi) is not Secure Boot signed.
@ -17,7 +17,7 @@ o Non Secure Boot signed exFAT UEFI drivers from EfiFs [2].
because they are licensed under GPLv3, cannot be Secure Boot signed.
o Secure Boot signed UEFI:NTFS bootloader binaries [3].
These drivers are the exact same as the binaries from release 2.2, except for
These drivers are the exact same as the binaries from release 2.3, except for
the addition of Microsoft's Secure Boot signature.
Note that, per Microsoft's current Secure Boot signing policies, the 32-bit
ARM bootloader (bootarm.efi) is not Secure Boot signed.

Binary file not shown.

View File

@ -1,8 +1,11 @@
SUBDIRS = ../.mingw bled ext2fs ms-sys syslinux/libfat syslinux/libinstaller syslinux/win libcdio/iso9660 libcdio/udf libcdio/driver ../res/loc
# As far as I can tell, the following libraries are *not* vulnerable to side-loading, so we link using their regular version:
NONVULNERABLE_LIBS = -lsetupapi -lole32 -lgdi32 -lshlwapi -lcrypt32 -lcomdlg32 -lcomctl32 -luuid
NONVULNERABLE_LIBS = -lsetupapi -lole32 -lgdi32 -lshlwapi -lcrypt32 -lcomctl32 -luuid
# The following libraries are vulnerable (or have an unknown vulnerability status), so we link using our delay-loaded replacement:
VULNERABLE_LIBS = -ldwmapi-delaylib -lvirtdisk-delaylib -lwintrust-delaylib
# Ideally there would also be virtdisk and wininet as delaylib's below, but the MinGW folks haven't quite sorted out delay-loading
# for x86_32 so as soon as you try to call APIs from these, the application will crash!
# See https://github.com/pbatard/rufus/issues/1877#issuecomment-1109683039 as well as https://github.com/pbatard/rufus/issues/2272
VULNERABLE_LIBS = -ldwmapi-delaylib -lversion-delaylib -lwintrust-delaylib
noinst_PROGRAMS = rufus

View File

@ -275,9 +275,12 @@ top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
SUBDIRS = ../.mingw bled ext2fs ms-sys syslinux/libfat syslinux/libinstaller syslinux/win libcdio/iso9660 libcdio/udf libcdio/driver ../res/loc
# As far as I can tell, the following libraries are *not* vulnerable to side-loading, so we link using their regular version:
NONVULNERABLE_LIBS = -lsetupapi -lole32 -lgdi32 -lshlwapi -lcrypt32 -lcomdlg32 -lcomctl32 -luuid
NONVULNERABLE_LIBS = -lsetupapi -lole32 -lgdi32 -lshlwapi -lcrypt32 -lcomctl32 -luuid
# The following libraries are vulnerable (or have an unknown vulnerability status), so we link using our delay-loaded replacement:
VULNERABLE_LIBS = -ldwmapi-delaylib -lvirtdisk-delaylib -lwintrust-delaylib
# Ideally there would also be virtdisk and wininet as delaylib's below, but the MinGW folks haven't quite sorted out delay-loading
# for x86_32 so as soon as you try to call APIs from these, the application will crash!
# See https://github.com/pbatard/rufus/issues/1877#issuecomment-1109683039 as well as https://github.com/pbatard/rufus/issues/2272
VULNERABLE_LIBS = -ldwmapi-delaylib -lversion-delaylib -lwintrust-delaylib
AM_V_WINDRES_0 = @echo " RC $@";$(WINDRES)
AM_V_WINDRES_1 = $(WINDRES)
AM_V_WINDRES_ = $(AM_V_WINDRES_$(AM_DEFAULT_VERBOSITY))

View File

@ -80,6 +80,7 @@ static uint8_t sha256db[] = {
0x78, 0x64, 0x8e, 0xf0, 0xc5, 0x00, 0x41, 0x75, 0xb9, 0xa8, 0xea, 0x33, 0x30, 0x14, 0xea, 0x02, 0xc9, 0x17, 0xf8, 0x23, 0xe7, 0x7a, 0x3e, 0xc9, 0xac, 0xd9, 0xd2, 0x2b, 0x46, 0x02, 0xf3, 0x6d, // syslinux-6.03/pre13/ldlinux.sys
0x7d, 0xa9, 0xc5, 0x21, 0x76, 0xb8, 0xaf, 0x01, 0x64, 0xea, 0x39, 0x21, 0x22, 0x44, 0xb1, 0x0a, 0xa0, 0xc7, 0x97, 0xe7, 0x65, 0xbb, 0x6b, 0x92, 0x69, 0xb5, 0x8b, 0xc9, 0xe5, 0x0a, 0x9f, 0x18, // syslinux-5.01/ldlinux.bss
0x82, 0x11, 0xfa, 0xe8, 0xaf, 0xf0, 0x23, 0x3f, 0x05, 0xa8, 0xb7, 0x8c, 0x58, 0x15, 0x25, 0xe2, 0x81, 0xac, 0x98, 0x23, 0x54, 0xa8, 0xc4, 0x3b, 0xb4, 0x96, 0x5e, 0x61, 0xdc, 0x98, 0xb4, 0x62, // syslinux-6.03/pre8/ldlinux.bss
0x83, 0x57, 0xaa, 0xd3, 0x6a, 0xec, 0x68, 0x21, 0xcb, 0xf2, 0x17, 0x4d, 0xb5, 0xd2, 0x09, 0xef, 0x2c, 0xd2, 0x62, 0x88, 0x12, 0x39, 0xeb, 0xc3, 0xf4, 0xc1, 0xcf, 0x55, 0xab, 0x10, 0xee, 0x55, // grub-2.12~rc1/core.img
0x83, 0x9b, 0xd0, 0x8a, 0xcb, 0x68, 0x47, 0xd6, 0x55, 0x07, 0xf1, 0x4e, 0x7a, 0x55, 0x6e, 0x91, 0xe6, 0x12, 0x9c, 0x47, 0x86, 0x3f, 0x7d, 0x61, 0xe2, 0xce, 0x6d, 0xb7, 0x8d, 0xf3, 0xd2, 0x3f, // syslinux-6.03/pre9/ldlinux.bss
0x87, 0xaa, 0x91, 0xf8, 0x7f, 0xba, 0x5f, 0x31, 0x79, 0x43, 0x08, 0xda, 0xa4, 0xa4, 0x8d, 0xad, 0x6c, 0xf6, 0xfa, 0x34, 0x26, 0x4d, 0x66, 0xb8, 0x84, 0xb8, 0xb9, 0xdc, 0x96, 0x42, 0xed, 0x86, // syslinux-5.02/ldlinux.sys
0x88, 0x14, 0xe5, 0x76, 0xab, 0xc1, 0xaa, 0x44, 0xdd, 0xe9, 0x43, 0xb0, 0xca, 0xae, 0xe8, 0x33, 0xa5, 0x81, 0x01, 0x42, 0x61, 0x4a, 0xde, 0xeb, 0x4c, 0xc7, 0x25, 0xe7, 0x8a, 0x50, 0x45, 0xb7, // syslinux-6.03/ldlinux.bss

View File

@ -1,7 +1,7 @@
/*
* Rufus: The Reliable USB Formatting Utility
* Device detection and enumeration
* Copyright © 2014-2023 Pete Batard <pete@akeo.ie>
* Copyright © 2014-2024 Pete Batard <pete@akeo.ie>
*
* 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
@ -465,7 +465,7 @@ BOOL GetDevices(DWORD devnum)
// Oh, and we also have card devices (e.g. 'SCSI\DiskO2Micro_SD_...') under the SCSI enumerator...
const char* scsi_disk_prefix = "SCSI\\Disk";
const char* scsi_card_name[] = {
"_SD_", "_SDHC_", "_MMC_", "_MS_", "_MSPro_", "_xDPicture_", "_O2Media_"
"_SD_", "_SDHC_", "_SDXC_", "_MMC_", "_MS_", "_MSPro_", "_xDPicture_", "_O2Media_"
};
const char* usb_speed_name[USB_SPEED_MAX] = { "USB", "USB 1.0", "USB 1.1", "USB 2.0", "USB 3.0", "USB 3.1" };
const char* windows_sandbox_vhd_label = "PortableBaseLayer";
@ -897,7 +897,7 @@ BOOL GetDevices(DWORD devnum)
break;
}
if (GetDriveLabel(drive_index, drive_letters, &label)) {
if (GetDriveLabel(drive_index, drive_letters, &label, FALSE)) {
if ((props.is_SCSI) && (!props.is_UASP) && (!props.is_VHD)) {
if (!props.is_Removable) {
// Non removables should have been eliminated above, but since we
@ -933,6 +933,10 @@ BOOL GetDevices(DWORD devnum)
uprintf("To use such a card, check 'List USB Hard Drives' under 'advanced drive properties'");
safe_free(devint_detail_data);
break;
} else if (props.is_VHD && IsMsDevDrive(drive_index)) {
uprintf("Device eliminated because it was detected as a Microsoft Dev Drive");
safe_free(devint_detail_data);
break;
}
// Windows 10 19H1 mounts a 'PortableBaseLayer' for its Windows Sandbox feature => unlist those
if (safe_strcmp(label, windows_sandbox_vhd_label) == 0) {

View File

@ -1,7 +1,7 @@
/*
* Rufus: The Reliable USB Formatting Utility
* DOS keyboard locale setup
* Copyright © 2011-2021 Pete Batard <pete@akeo.ie>
* Copyright © 2011-2024 Pete Batard <pete@akeo.ie>
*
* 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
@ -197,8 +197,8 @@ static kb_list fd_kb_list[] = {
static int ms_get_kbdrv(const char* kb)
{
unsigned int i, j;
for (i=0; i<ARRAYSIZE(ms_kb_list); i++) {
for (j=0; j<ms_kb_list[i].size; j++) {
for (i = 0; i<ARRAYSIZE(ms_kb_list); i++) {
for (j = 0; j < ms_kb_list[i].size; j++) {
if (safe_strcmp(ms_kb_list[i].list[j], kb) == 0) {
return i;
}
@ -210,8 +210,8 @@ static int ms_get_kbdrv(const char* kb)
static int fd_get_kbdrv(const char* kb)
{
unsigned int i, j;
for (i=0; i<ARRAYSIZE(fd_kb_list); i++) {
for (j=0; j<fd_kb_list[i].size; j++) {
for (i = 0; i < ARRAYSIZE(fd_kb_list); i++) {
for (j = 0; j < fd_kb_list[i].size; j++) {
if (safe_strcmp(fd_kb_list[i].list[j], kb) == 0) {
return i;
}
@ -250,7 +250,7 @@ static const char* kb_hr_list[][2] = {
{"is", "Icelandic"},
{"it", "Italian"},
{"jp", "Japanese"},
// {"ko", "Korean"}, // Unsupported by FreeDOS?
// {"ko", "Korean"}, // Unsupported by FreeDOS
{"nl", "Dutch"},
{"no", "Norwegian"},
{"pl", "Polish"},
@ -270,7 +270,7 @@ static const char* kb_hr_list[][2] = {
{"lv", "Latvian"},
{"lt", "Lithuanian"},
{"tj", "Tajik"},
// {"fa", "Persian"}; // Unsupported by FreeDOS?
// {"fa", "Persian"}; // Unsupported by FreeDOS
{"vi", "Vietnamese"},
{"hy", "Armenian"},
{"az", "Azeri"},
@ -288,7 +288,7 @@ static const char* kb_hr_list[][2] = {
static const char* kb_to_hr(const char* kb)
{
int i;
for (i=0; i<ARRAYSIZE(kb_hr_list); i++) {
for (i = 0; i < ARRAYSIZE(kb_hr_list); i++) {
if (safe_strcmp(kb, kb_hr_list[i][0]) == 0) {
return kb_hr_list[i][1];
}
@ -426,7 +426,7 @@ static cp_list cp_hr_list[] = {
static const char* cp_to_hr(ULONG cp)
{
int i;
for (i=0; i<ARRAYSIZE(cp_hr_list); i++) {
for (i = 0; i < ARRAYSIZE(cp_hr_list); i++) {
if (cp_hr_list[i].cp == cp) {
return cp_hr_list[i].name;
}
@ -449,13 +449,13 @@ static const char* get_kb(void)
// need an KLID which GetKeyboardLayoutNameA() does return ...but only as a
// string of an hex value...
GetKeyboardLayoutNameA(kbid_str);
if (sscanf(kbid_str, "%x", &kbid) == 0) {
uprintf("Could not scan keyboard layout name - falling back to US as default\n");
if (sscanf(kbid_str, "%x", &kbid) <= 0) {
uprintf("Could not scan keyboard layout name - defaulting to US");
kbid = 0x00000409;
}
uprintf("Windows KBID 0x%08x\n", kbid);
for (pass=0; pass<3; pass++) {
for (pass = 0; pass < 3; pass++) {
// Some of these return values are defined in
// HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout\DosKeybCodes
// Others are picked up in FreeDOS official keyboard layouts, v3.0
@ -748,12 +748,12 @@ static const char* get_kb(void)
} else if (pass == 1) {
// If we still didn't get a match, use the system's primary language
kbid = PRIMARYLANGID(GetSystemDefaultLangID());
uprintf("Unable to match KBID, trying LangID 0x%04x\n", kbid);
uprintf("Unable to match KBID, trying LangID 0x%04x", kbid);
}
break;
}
}
uprintf("Unable to match KBID and LangID - defaulting to US\n");
uprintf("Unable to match KBID and LangID - defaulting to US");
return "us";
}
@ -976,14 +976,14 @@ BOOL SetDOSLocale(const char* path, BOOL bFreeDOS)
// First handle the codepage
kb = get_kb();
// We have a keyboard ID, but that doesn't mean it's supported
kbdrv = bFreeDOS?fd_get_kbdrv(kb):ms_get_kbdrv(kb);
kbdrv = bFreeDOS ? fd_get_kbdrv(kb) : ms_get_kbdrv(kb);
if (kbdrv < 0) {
uprintf("Keyboard id '%s' is not supported - falling back to 'us'\n", kb);
uprintf("Keyboard id '%s' is not supported - falling back to 'us'", kb);
kb = "us";
kbdrv = bFreeDOS?fd_get_kbdrv(kb):ms_get_kbdrv(kb); // Always succeeds
kbdrv = bFreeDOS ? fd_get_kbdrv(kb) : ms_get_kbdrv(kb); // Always succeeds
}
assert(kbdrv >= 0);
uprintf("Will use DOS keyboard '%s' [%s]\n", kb, kb_to_hr(kb));
uprintf("Will use DOS keyboard '%s' [%s]", kb, kb_to_hr(kb));
// Now get a codepage
cp = GetOEMCP();
@ -994,16 +994,16 @@ BOOL SetDOSLocale(const char* path, BOOL bFreeDOS)
(char*)&actual_cp, sizeof(actual_cp)))
cp = actual_cp;
}
egadrv = bFreeDOS?fd_get_ega(cp):ms_get_ega(cp);
egadrv = bFreeDOS ? fd_get_ega(cp) : ms_get_ega(cp);
if (egadrv == NULL) {
// We need to use the fallback CP from the keyboard we got above, as 437 is not always available
uprintf("Unable to find an EGA file with codepage %d [%s]\n", cp, cp_to_hr(cp));
uprintf("Unable to find an EGA file with codepage %d [%s]", cp, cp_to_hr(cp));
cp = kbdrv_data[kbdrv].default_cp;
egadrv = bFreeDOS?"ega.cpx":"ega.cpi";
egadrv = bFreeDOS ? "ega.cpx" : "ega.cpi";
} else if (bFreeDOS) {
cp = fd_upgrade_cp(cp);
}
uprintf("Will use codepage %d [%s]\n", cp, cp_to_hr(cp));
uprintf("Will use codepage %d [%s]", cp, cp_to_hr(cp));
if ((cp == 437) && (strcmp(kb, "us") == 0)) {
// Nothing much to do if US/US - just notify in autoexec.bat
@ -1011,14 +1011,14 @@ BOOL SetDOSLocale(const char* path, BOOL bFreeDOS)
static_strcat(filename, "\\AUTOEXEC.BAT");
fd = fopen(filename, "w+");
if (fd == NULL) {
uprintf("Unable to create 'AUTOEXEC.BAT': %s.\n", WindowsErrorString());
uprintf("Unable to create 'AUTOEXEC.BAT': %s", WindowsErrorString());
return FALSE;
}
fprintf(fd, "@echo off\n");
fprintf(fd, "set PATH=.;\\;\\LOCALE\n");
fprintf(fd, "echo Using %s keyboard with %s codepage [%d]\n", kb_to_hr("us"), cp_to_hr(437), 437);
fclose(fd);
uprintf("Successfully wrote 'AUTOEXEC.BAT'\n");
uprintf("Successfully wrote 'AUTOEXEC.BAT'");
return TRUE;
}
@ -1027,7 +1027,7 @@ BOOL SetDOSLocale(const char* path, BOOL bFreeDOS)
static_strcat(filename, "\\CONFIG.SYS");
fd = fopen(filename, "w+");
if (fd == NULL) {
uprintf("Unable to create 'CONFIG.SYS': %s.\n", WindowsErrorString());
uprintf("Unable to create 'CONFIG.SYS': %s.", WindowsErrorString());
return FALSE;
}
if (bFreeDOS) {
@ -1045,14 +1045,14 @@ BOOL SetDOSLocale(const char* path, BOOL bFreeDOS)
bFreeDOS?"MENU ":"MENUITEM=", bFreeDOS?')':',', kb_to_hr("us"), cp_to_hr(437), 437);
fprintf(fd, "%s", bFreeDOS?"MENU\n12?\n":"[1]\ndevice=\\locale\\display.sys con=(ega,,1)\n[2]\n");
fclose(fd);
uprintf("Successfully wrote 'CONFIG.SYS'\n");
uprintf("Successfully wrote 'CONFIG.SYS'");
// AUTOEXEC.BAT
static_strcpy(filename, path);
static_strcat(filename, "\\AUTOEXEC.BAT");
fd = fopen(filename, "w+");
if (fd == NULL) {
uprintf("Unable to create 'AUTOEXEC.BAT': %s.\n", WindowsErrorString());
uprintf("Unable to create 'AUTOEXEC.BAT': %s", WindowsErrorString());
return FALSE;
}
fprintf(fd, "@echo off\n");
@ -1066,7 +1066,7 @@ BOOL SetDOSLocale(const char* path, BOOL bFreeDOS)
fprintf(fd, "keyb %s,,\\locale\\%s\n", kb, kbdrv_data[kbdrv].name);
fprintf(fd, ":2\n");
fclose(fd);
uprintf("Successfully wrote 'AUTOEXEC.BAT'\n");
uprintf("Successfully wrote 'AUTOEXEC.BAT'");
return TRUE;
}

View File

@ -1,7 +1,7 @@
/*
* Rufus: The Reliable USB Formatting Utility
* Drive access function calls
* Copyright © 2011-2023 Pete Batard <pete@akeo.ie>
* Copyright © 2011-2024 Pete Batard <pete@akeo.ie>
*
* 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
@ -74,7 +74,7 @@ PF_TYPE_DECL(NTAPI, NTSTATUS, NtQueryVolumeInformationFile, (HANDLE, PIO_STATUS_
RUFUS_DRIVE_INFO SelectedDrive;
extern BOOL write_as_esp;
extern windows_version_t WindowsVersion;
uint64_t partition_offset[PI_MAX];
int partition_index[PI_MAX];
uint64_t persistence_size = 0;
/*
@ -172,8 +172,7 @@ static HANDLE GetHandle(char* Path, BOOL bLockDrive, BOOL bWriteAccess, BOOL bWr
uprintf("Warning: Could not obtain exclusive rights. Retrying with write sharing enabled...");
bWriteShare = TRUE;
// Try to report the process that is locking the drive
// We also use bit 6 as a flag to indicate that SearchProcess was called.
access_mask = SearchProcess(DevPath, SEARCH_PROCESS_TIMEOUT, TRUE, TRUE, FALSE) | 0x40;
access_mask = GetProcessSearch(SEARCH_PROCESS_TIMEOUT, 0x07, FALSE);
}
Sleep(DRIVE_ACCESS_TIMEOUT / DRIVE_ACCESS_RETRIES);
}
@ -203,9 +202,7 @@ static HANDLE GetHandle(char* Path, BOOL bLockDrive, BOOL bWriteAccess, BOOL bWr
uprintf("Could not lock access to %s: %s", Path, WindowsErrorString());
// See if we can report the processes are accessing the drive
if (!IS_ERROR(FormatStatus) && (access_mask == 0))
// Double the search process timeout here, as Windows is so bloated with processes
// that 10 seconds has become way too small to get much of any results these days...
access_mask = SearchProcess(DevPath, 2 * SEARCH_PROCESS_TIMEOUT, TRUE, TRUE, FALSE);
access_mask = GetProcessSearch(SEARCH_PROCESS_TIMEOUT, 0x07, FALSE);
// Try to continue if the only access rights we saw were for read-only
if ((access_mask & 0x07) != 0x01)
safe_closehandle(hDrive);
@ -395,7 +392,7 @@ char* AltGetLogicalName(DWORD DriveIndex, uint64_t PartitionOffset, BOOL bKeepTr
if (PartitionOffset == 0) {
i = 0;
} else if (matching_drive) {
for (i = 0; (i < MAX_PARTITIONS) && (PartitionOffset != SelectedDrive.PartitionOffset[i]); i++);
for (i = 0; (i < MAX_PARTITIONS) && (PartitionOffset != SelectedDrive.Partition[i].Offset); i++);
if (i >= MAX_PARTITIONS) {
suprintf("Error: Could not find a partition at offset %lld on this disk", PartitionOffset);
goto out;
@ -431,11 +428,11 @@ char* GetExtPartitionName(DWORD DriveIndex, uint64_t PartitionOffset)
if (DriveIndex != SelectedDrive.DeviceNumber)
goto out;
CheckDriveIndex(DriveIndex);
for (i = 0; (i < MAX_PARTITIONS) && (PartitionOffset != SelectedDrive.PartitionOffset[i]); i++);
for (i = 0; (i < MAX_PARTITIONS) && (PartitionOffset != SelectedDrive.Partition[i].Offset); i++);
if (i >= MAX_PARTITIONS)
goto out;
static_sprintf(volume_name, "\\\\.\\PhysicalDrive%lu %I64u %I64u", DriveIndex,
SelectedDrive.PartitionOffset[i], SelectedDrive.PartitionSize[i]);
SelectedDrive.Partition[i].Offset, SelectedDrive.Partition[i].Size);
ret = safe_strdup(volume_name);
out:
return ret;
@ -1314,7 +1311,7 @@ BOOL IsDriveLetterInUse(const char drive_letter)
* Return the drive letter and volume label
* If the drive doesn't have a volume assigned, space is returned for the letter
*/
BOOL GetDriveLabel(DWORD DriveIndex, char* letters, char** label)
BOOL GetDriveLabel(DWORD DriveIndex, char* letters, char** label, BOOL bSilent)
{
HANDLE hPhysical;
DWORD size, error;
@ -1350,10 +1347,10 @@ BOOL GetDriveLabel(DWORD DriveIndex, char* letters, char** label)
if (DeviceIoControl(hPhysical, IOCTL_STORAGE_CHECK_VERIFY, NULL, 0, NULL, 0, &size, NULL))
AutorunLabel = get_token_data_file("label", AutorunPath);
else if (GetLastError() == ERROR_NOT_READY)
uprintf("Ignoring 'autorun.inf' label for drive %c: No media", toupper(letters[0]));
suprintf("Ignoring 'autorun.inf' label for drive %c: No media", toupper(letters[0]));
safe_closehandle(hPhysical);
if (AutorunLabel != NULL) {
uprintf("Using 'autorun.inf' label for drive %c: '%s'", toupper(letters[0]), AutorunLabel);
suprintf("Using 'autorun.inf' label for drive %c: '%s'", toupper(letters[0]), AutorunLabel);
static_strcpy(VolumeLabel, AutorunLabel);
safe_free(AutorunLabel);
*label = VolumeLabel;
@ -1541,7 +1538,7 @@ static BOOL StoreEspInfo(GUID* guid)
static_sprintf(key_name[0], "ToggleEsp%02u", j);
str = ReadSettingStr(key_name[0]);
if ((str == NULL) || (str[0] == 0))
return WriteSettingStr(key_name[0], GuidToString(guid));
return WriteSettingStr(key_name[0], GuidToString(guid, TRUE));
}
// All slots are used => Move every key down and add to last slot
// NB: No, we don't care that the slot we remove may not be the oldest.
@ -1550,7 +1547,7 @@ static BOOL StoreEspInfo(GUID* guid)
static_sprintf(key_name[1], "ToggleEsp%02u", j + 1);
WriteSettingStr(key_name[0], ReadSettingStr(key_name[1]));
}
return WriteSettingStr(key_name[1], GuidToString(guid));
return WriteSettingStr(key_name[1], GuidToString(guid, TRUE));
}
static GUID* GetEspGuid(uint8_t index)
@ -1871,8 +1868,7 @@ BOOL GetDrivePartitionData(DWORD DriveIndex, char* FileSystemName, DWORD FileSys
return FALSE;
SelectedDrive.nPartitions = 0;
memset(SelectedDrive.PartitionOffset, 0, sizeof(SelectedDrive.PartitionOffset));
memset(SelectedDrive.PartitionSize, 0, sizeof(SelectedDrive.PartitionSize));
memset(SelectedDrive.Partition, 0, sizeof(SelectedDrive.Partition));
// Populate the filesystem data
FileSystemName[0] = 0;
volume_name = GetLogicalName(DriveIndex, 0, TRUE, FALSE);
@ -1964,8 +1960,8 @@ BOOL GetDrivePartitionData(DWORD DriveIndex, char* FileSystemName, DWORD FileSys
}
}
if (i < MAX_PARTITIONS) {
SelectedDrive.PartitionOffset[i] = DriveLayout->PartitionEntry[i].StartingOffset.QuadPart;
SelectedDrive.PartitionSize[i] = DriveLayout->PartitionEntry[i].PartitionLength.QuadPart;
SelectedDrive.Partition[i].Offset = DriveLayout->PartitionEntry[i].StartingOffset.QuadPart;
SelectedDrive.Partition[i].Size = DriveLayout->PartitionEntry[i].PartitionLength.QuadPart;
}
suprintf(" Type: %s (0x%02x)\r\n Detected File System: %s\r\n"
" Size: %s (%lld bytes)\r\n Start Sector: %lld, Boot: %s",
@ -1990,23 +1986,24 @@ BOOL GetDrivePartitionData(DWORD DriveIndex, char* FileSystemName, DWORD FileSys
case PARTITION_STYLE_GPT:
SelectedDrive.PartitionStyle = PARTITION_STYLE_GPT;
suprintf("Partition type: GPT, NB Partitions: %d", DriveLayout->PartitionCount);
suprintf("Disk GUID: %s", GuidToString(&DriveLayout->Gpt.DiskId));
suprintf("Disk GUID: %s", GuidToString(&DriveLayout->Gpt.DiskId, TRUE));
suprintf("Max parts: %d, Start Offset: %" PRIi64 ", Usable = %" PRIi64 " bytes",
DriveLayout->Gpt.MaxPartitionCount, DriveLayout->Gpt.StartingUsableOffset.QuadPart, DriveLayout->Gpt.UsableLength.QuadPart);
for (i = 0; i < DriveLayout->PartitionCount; i++) {
if (i < MAX_PARTITIONS) {
SelectedDrive.PartitionOffset[i] = DriveLayout->PartitionEntry[i].StartingOffset.QuadPart;
SelectedDrive.PartitionSize[i] = DriveLayout->PartitionEntry[i].PartitionLength.QuadPart;
SelectedDrive.Partition[i].Offset = DriveLayout->PartitionEntry[i].StartingOffset.QuadPart;
SelectedDrive.Partition[i].Size = DriveLayout->PartitionEntry[i].PartitionLength.QuadPart;
wcscpy(SelectedDrive.Partition[i].Name, DriveLayout->PartitionEntry[i].Gpt.Name);
}
SelectedDrive.nPartitions++;
isUefiNtfs = (wcscmp(DriveLayout->PartitionEntry[i].Gpt.Name, L"UEFI:NTFS") == 0);
suprintf("Partition %d%s:\r\n Type: %s", i+1, isUefiNtfs ? " (UEFI:NTFS)" : "",
suprintf("Partition %d%s:\r\n Type: %s", i + 1, isUefiNtfs ? " (UEFI:NTFS)" : "",
GetGPTPartitionType(&DriveLayout->PartitionEntry[i].Gpt.PartitionType));
if (DriveLayout->PartitionEntry[i].Gpt.Name[0] != 0)
suprintf(" Name: '%S'", DriveLayout->PartitionEntry[i].Gpt.Name);
suprintf(" Detected File System: %s", GetFsName(hPhysical, DriveLayout->PartitionEntry[i].StartingOffset));
suprintf(" ID: %s\r\n Size: %s (%" PRIi64 " bytes)\r\n Start Sector: %" PRIi64 ", Attributes: 0x%016" PRIX64,
GuidToString(&DriveLayout->PartitionEntry[i].Gpt.PartitionId),
GuidToString(&DriveLayout->PartitionEntry[i].Gpt.PartitionId, TRUE),
SizeToHumanReadable(DriveLayout->PartitionEntry[i].PartitionLength.QuadPart, TRUE, FALSE),
DriveLayout->PartitionEntry[i].PartitionLength,
DriveLayout->PartitionEntry[i].StartingOffset.QuadPart / SelectedDrive.SectorSize,
@ -2235,15 +2232,17 @@ BOOL RemountVolume(char* drive_name, BOOL bSilent)
* (especially IOCTL_DISK_UPDATE_PROPERTIES is *USELESS*), and therefore the OS will try to
* read the file system data at an old location, even if the partition has just been deleted.
*/
static BOOL ClearPartition(HANDLE hDrive, LARGE_INTEGER offset, DWORD size)
static BOOL ClearPartition(HANDLE hDrive, uint64_t offset, DWORD size)
{
BOOL r = FALSE;
uint8_t* buffer = calloc(size, 1);
LARGE_INTEGER li_offset;
if (buffer == NULL)
return FALSE;
if (!SetFilePointerEx(hDrive, offset, NULL, FILE_BEGIN)) {
li_offset.QuadPart = offset;
if (!SetFilePointerEx(hDrive, li_offset, NULL, FILE_BEGIN)) {
free(buffer);
return FALSE;
}
@ -2263,41 +2262,44 @@ static BOOL ClearPartition(HANDLE hDrive, LARGE_INTEGER offset, DWORD size)
BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL mbr_uefi_marker, uint8_t extra_partitions)
{
const char* PartitionTypeName[] = { "MBR", "GPT", "SFD" };
const wchar_t *extra_part_name = L"", *main_part_name = write_as_esp ? L"EFI System Partition" : L"Main Data Partition";
const LONGLONG main_part_size = write_as_esp ? MAX_ISO_TO_ESP_SIZE * MB : SelectedDrive.DiskSize;
const LONGLONG bytes_per_track = ((LONGLONG)SelectedDrive.SectorsPerTrack) * SelectedDrive.SectorSize;
const DWORD size_to_clear = MAX_SECTORS_TO_CLEAR * SelectedDrive.SectorSize;
uint8_t* buffer;
uint64_t last_offset = SelectedDrive.DiskSize;
size_t uefi_ntfs_size = 0;
CREATE_DISK CreateDisk = {PARTITION_STYLE_RAW, {{0}}};
DRIVE_LAYOUT_INFORMATION_EX4 DriveLayoutEx = {0};
BOOL r;
DWORD i, size, bufsize, pn = 0;
LONGLONG main_part_size_in_sectors, extra_part_size_in_tracks = 0;
DWORD pi = 0, mi, i, size, bufsize;
CREATE_DISK CreateDisk = { PARTITION_STYLE_RAW, { { 0 } } };
DRIVE_LAYOUT_INFORMATION_EX4 DriveLayoutEx = { 0 };
// Go for a 260 MB sized ESP by default to keep everyone happy, including 4K sector users:
// https://docs.microsoft.com/en-us/windows-hardware/manufacture/desktop/configure-uefigpt-based-hard-drive-partitions
// and folks using MacOS: https://github.com/pbatard/rufus/issues/979
LONGLONG esp_size = 260 * MB;
LONGLONG ClusterSize = (LONGLONG)ComboBox_GetCurItemData(hClusterSize);
PrintInfoDebug(0, MSG_238, PartitionTypeName[partition_style]);
if (ClusterSize == 0)
ClusterSize = 0x200;
if (partition_style == PARTITION_STYLE_SFD)
// Nothing to do
return TRUE;
if (extra_partitions & XP_UEFI_NTFS) {
uefi_ntfs_size = GetResourceSize(hMainInstance, MAKEINTRESOURCEA(IDR_UEFI_NTFS), _RT_RCDATA, "uefi-ntfs.img");
if (uefi_ntfs_size == 0)
if (uefi_ntfs_size == 0) {
uprintf("Could not access embedded 'uefi-ntfs.img'");
return FALSE;
}
}
memset(partition_offset, 0, sizeof(partition_offset));
memset(SelectedDrive.PartitionOffset, 0, sizeof(SelectedDrive.PartitionOffset));
memset(SelectedDrive.PartitionSize, 0, sizeof(SelectedDrive.PartitionSize));
// Compute the start offset of our first partition
memset(partition_index, 0, sizeof(partition_index));
memset(SelectedDrive.Partition, 0, sizeof(SelectedDrive.Partition));
// Compute the starting offset of the first partition
if ((partition_style == PARTITION_STYLE_GPT) || (!IsChecked(IDC_OLD_BIOS_FIXES))) {
// Go with the MS 1 MB wastage at the beginning...
DriveLayoutEx.PartitionEntry[pn].StartingOffset.QuadPart = MB;
SelectedDrive.Partition[pi].Offset = 1 * MB;
} else {
// Some folks appear to think that 'Fixes for old BIOSes' is some kind of magic
// wand and are adamant to try to apply them when creating *MODERN* VHD drives.
@ -2307,14 +2309,10 @@ BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL m
// CHS sizes that IBM imparted upon us. Long story short, we now align to a
// cylinder size that is itself aligned to the cluster size.
// If this actually breaks old systems, please send your complaints to IBM.
LONGLONG ClusterSize = (LONGLONG)ComboBox_GetCurItemData(hClusterSize);
if (ClusterSize == 0)
ClusterSize = 0x200;
DriveLayoutEx.PartitionEntry[pn].StartingOffset.QuadPart =
((bytes_per_track + (ClusterSize - 1)) / ClusterSize) * ClusterSize;
SelectedDrive.Partition[pi].Offset = HI_ALIGN_X_TO_Y(bytes_per_track, ClusterSize);
// GRUB2 no longer fits in the usual 31½ KB that the above computation provides
// so just unconditionally double that size and get on with it.
DriveLayoutEx.PartitionEntry[pn].StartingOffset.QuadPart *= 2;
SelectedDrive.Partition[pi].Offset *= 2;
}
// Having the ESP up front may help (and is the Microsoft recommended way) but this
@ -2323,22 +2321,16 @@ BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL m
if (((SelectedDrive.MediaType == FixedMedia) || (WindowsVersion.BuildNumber > 15000)) &&
(extra_partitions & XP_ESP)) {
assert(partition_style == PARTITION_STYLE_GPT);
extra_part_name = L"EFI System Partition";
DriveLayoutEx.PartitionEntry[pn].PartitionLength.QuadPart = esp_size;
DriveLayoutEx.PartitionEntry[pn].Gpt.PartitionType = PARTITION_GENERIC_ESP;
uprintf("● Creating %S (offset: %lld, size: %s)", extra_part_name, DriveLayoutEx.PartitionEntry[pn].StartingOffset.QuadPart,
SizeToHumanReadable(DriveLayoutEx.PartitionEntry[pn].PartitionLength.QuadPart, TRUE, FALSE));
IGNORE_RETVAL(CoCreateGuid(&DriveLayoutEx.PartitionEntry[pn].Gpt.PartitionId));
wcsncpy(DriveLayoutEx.PartitionEntry[pn].Gpt.Name, extra_part_name, ARRAYSIZE(DriveLayoutEx.PartitionEntry[pn].Gpt.Name));
// Zero the first sectors from this partition to avoid file system caching issues
if (!ClearPartition(hDrive, DriveLayoutEx.PartitionEntry[pn].StartingOffset, size_to_clear))
uprintf("Could not zero %S: %s", extra_part_name, WindowsErrorString());
SelectedDrive.PartitionOffset[pn] = DriveLayoutEx.PartitionEntry[pn].StartingOffset.QuadPart;
SelectedDrive.PartitionSize[pn] = DriveLayoutEx.PartitionEntry[pn].PartitionLength.QuadPart;
partition_offset[PI_ESP] = SelectedDrive.PartitionOffset[pn];
pn++;
DriveLayoutEx.PartitionEntry[pn].StartingOffset.QuadPart = DriveLayoutEx.PartitionEntry[pn - 1].StartingOffset.QuadPart +
DriveLayoutEx.PartitionEntry[pn - 1].PartitionLength.QuadPart;
partition_index[PI_ESP] = pi;
wcscpy(SelectedDrive.Partition[pi].Name, L"EFI System Partition");
SelectedDrive.Partition[pi].Size = esp_size;
SelectedDrive.Partition[pi + 1].Offset = SelectedDrive.Partition[pi].Offset + SelectedDrive.Partition[pi].Size;
// Align next partition to track and cluster
SelectedDrive.Partition[pi + 1].Offset = HI_ALIGN_X_TO_Y(SelectedDrive.Partition[pi + 1].Offset, bytes_per_track);
if (ClusterSize % SelectedDrive.SectorSize == 0)
SelectedDrive.Partition[pi + 1].Offset = LO_ALIGN_X_TO_Y(SelectedDrive.Partition[pi + 1].Offset, ClusterSize);
assert(SelectedDrive.Partition[pi + 1].Offset >= SelectedDrive.Partition[pi].Offset + SelectedDrive.Partition[pi].Size);
pi++;
// Clear the extra partition we processed
extra_partitions &= ~(XP_ESP);
}
@ -2346,182 +2338,165 @@ BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL m
// If required, set the MSR partition (GPT only - must be created before the data part)
if (extra_partitions & XP_MSR) {
assert(partition_style == PARTITION_STYLE_GPT);
extra_part_name = L"Microsoft Reserved Partition";
DriveLayoutEx.PartitionEntry[pn].PartitionLength.QuadPart = 128*MB;
DriveLayoutEx.PartitionEntry[pn].Gpt.PartitionType = PARTITION_MICROSOFT_RESERVED;
uprintf("● Creating %S (offset: %lld, size: %s)", extra_part_name, DriveLayoutEx.PartitionEntry[pn].StartingOffset.QuadPart,
SizeToHumanReadable(DriveLayoutEx.PartitionEntry[pn].PartitionLength.QuadPart, TRUE, FALSE));
IGNORE_RETVAL(CoCreateGuid(&DriveLayoutEx.PartitionEntry[pn].Gpt.PartitionId));
wcsncpy(DriveLayoutEx.PartitionEntry[pn].Gpt.Name, extra_part_name, ARRAYSIZE(DriveLayoutEx.PartitionEntry[pn].Gpt.Name));
// Zero the first sectors from this partition to avoid file system caching issues
if (!ClearPartition(hDrive, DriveLayoutEx.PartitionEntry[pn].StartingOffset, size_to_clear))
uprintf("Could not zero %S: %s", extra_part_name, WindowsErrorString());
SelectedDrive.PartitionOffset[pn] = DriveLayoutEx.PartitionEntry[pn].StartingOffset.QuadPart;
SelectedDrive.PartitionSize[pn] = DriveLayoutEx.PartitionEntry[pn].PartitionLength.QuadPart;
pn++;
DriveLayoutEx.PartitionEntry[pn].StartingOffset.QuadPart = DriveLayoutEx.PartitionEntry[pn-1].StartingOffset.QuadPart +
DriveLayoutEx.PartitionEntry[pn-1].PartitionLength.QuadPart;
// Clear the extra partition we processed
wcscpy(SelectedDrive.Partition[pi].Name, L"Microsoft Reserved Partition");
SelectedDrive.Partition[pi].Size = 128 * MB;
SelectedDrive.Partition[pi + 1].Offset = SelectedDrive.Partition[pi].Offset + SelectedDrive.Partition[pi].Size;
SelectedDrive.Partition[pi + 1].Offset = HI_ALIGN_X_TO_Y(SelectedDrive.Partition[pi + 1].Offset, bytes_per_track);
if (ClusterSize % SelectedDrive.SectorSize == 0)
SelectedDrive.Partition[pi + 1].Offset = LO_ALIGN_X_TO_Y(SelectedDrive.Partition[pi + 1].Offset, ClusterSize);
assert(SelectedDrive.Partition[pi + 1].Offset >= SelectedDrive.Partition[pi].Offset + SelectedDrive.Partition[pi].Size);
pi++;
extra_partitions &= ~(XP_MSR);
}
// Set our main data partition
if (write_as_esp) {
// Align ESP to 64 MB while leaving at least 32 MB free space
esp_size = max(esp_size, ((((LONGLONG)img_report.projected_size / MB) + 96) / 64) * 64 * MB);
main_part_size_in_sectors = (esp_size - DriveLayoutEx.PartitionEntry[pn].StartingOffset.QuadPart) /
SelectedDrive.SectorSize;
} else {
main_part_size_in_sectors = (main_part_size - DriveLayoutEx.PartitionEntry[pn].StartingOffset.QuadPart) /
// Need 33 sectors at the end for secondary GPT
SelectedDrive.SectorSize - ((partition_style == PARTITION_STYLE_GPT) ? 33 : 0);
}
// Reserve an entry for the main partition
partition_index[PI_MAIN] = pi++;
// Shorthand for the main index.
mi = partition_index[PI_MAIN];
wcscpy(SelectedDrive.Partition[mi].Name, write_as_esp ? L"EFI System Partition" : L"Main Data Partition");
if (extra_partitions) {
// Adjust the size according to extra partitions (which we always align to a track)
if (extra_partitions & XP_ESP) {
extra_part_name = L"EFI System";
extra_part_size_in_tracks = (esp_size + bytes_per_track - 1) / bytes_per_track;
} else if (extra_partitions & XP_UEFI_NTFS) {
extra_part_name = L"UEFI:NTFS";
extra_part_size_in_tracks = (max(MIN_EXTRA_PART_SIZE, uefi_ntfs_size) + bytes_per_track - 1) / bytes_per_track;
} else if ((extra_partitions & XP_CASPER)) {
// TODO: Should we align these to cluster as well?
if (extra_partitions & XP_PERSISTENCE) {
assert(persistence_size != 0);
extra_part_name = L"Linux Persistence";
extra_part_size_in_tracks = persistence_size / bytes_per_track;
} else if (extra_partitions & XP_COMPAT) {
extra_part_name = L"BIOS Compatibility";
extra_part_size_in_tracks = 1; // One track for the extra partition
} else {
assert(FALSE);
partition_index[PI_CASPER] = pi;
wcscpy(SelectedDrive.Partition[pi].Name, L"Linux Persistence");
SelectedDrive.Partition[pi++].Size = HI_ALIGN_X_TO_Y(persistence_size, bytes_per_track);
}
// NB: Because we already subtracted the backup GPT size from the main partition size and
// this extra partition is indexed on main size, it does not overflow into the backup GPT.
main_part_size_in_sectors = ((main_part_size_in_sectors / SelectedDrive.SectorsPerTrack) -
extra_part_size_in_tracks) * SelectedDrive.SectorsPerTrack;
if (extra_partitions & XP_ESP) {
partition_index[PI_ESP] = pi;
wcscpy(SelectedDrive.Partition[pi].Name, L"EFI System Partition");
SelectedDrive.Partition[pi++].Size = HI_ALIGN_X_TO_Y(esp_size, bytes_per_track);
} else if (extra_partitions & XP_UEFI_NTFS) {
partition_index[PI_UEFI_NTFS] = pi;
wcscpy(SelectedDrive.Partition[pi].Name, L"UEFI:NTFS");
SelectedDrive.Partition[pi++].Size = HI_ALIGN_X_TO_Y(uefi_ntfs_size, bytes_per_track);
} else if (extra_partitions & XP_COMPAT) {
wcscpy(SelectedDrive.Partition[pi].Name, L"BIOS Compatibility");
SelectedDrive.Partition[pi++].Size = bytes_per_track; // One track for the extra partition
}
assert(pi <= MAX_PARTITIONS);
}
if (main_part_size_in_sectors <= 0) {
uprintf("Error: Invalid %S size", main_part_name);
// Compute the offsets of the extra partitions (which we always align to a track)
last_offset = SelectedDrive.DiskSize;
if (partition_style == PARTITION_STYLE_GPT)
last_offset -= 33ULL * SelectedDrive.SectorSize;
for (i = pi - 1; i > mi; i--) {
assert(SelectedDrive.Partition[i].Size < last_offset);
SelectedDrive.Partition[i].Offset = LO_ALIGN_X_TO_Y(last_offset - SelectedDrive.Partition[i].Size, bytes_per_track);
last_offset = SelectedDrive.Partition[i].Offset;
}
// With the above, Compute the main partition size (which we align to a track)
assert(last_offset > SelectedDrive.Partition[mi].Offset);
SelectedDrive.Partition[mi].Size = LO_ALIGN_X_TO_Y(last_offset - SelectedDrive.Partition[mi].Offset, bytes_per_track);
// Try to make sure that the main partition size is a multiple of the cluster size
// This can be especially important when trying to capture an NTFS partition as FFU, as, when
// the NTFS partition is aligned to cluster size, the FFU capture parses the NTFS allocated
// map to only record clusters that are in use, whereas, if not aligned, the FFU capture uses
// a full sector by sector scan of the NTFS partition and records any non-zero garbage, which
// may include garbage leftover data from a previous reformat...
if (ClusterSize % SelectedDrive.SectorSize == 0)
SelectedDrive.Partition[mi].Size = LO_ALIGN_X_TO_Y(SelectedDrive.Partition[mi].Size, ClusterSize);
if (SelectedDrive.Partition[mi].Size <= 0) {
uprintf("Error: Invalid %S size", SelectedDrive.Partition[mi].Name);
return FALSE;
}
uprintf("● Creating %S (offset: %lld, size: %s)", main_part_name, DriveLayoutEx.PartitionEntry[pn].StartingOffset.QuadPart,
SizeToHumanReadable(main_part_size_in_sectors * SelectedDrive.SectorSize, TRUE, FALSE));
// Zero the beginning of this partition to avoid conflicting leftovers
if (!ClearPartition(hDrive, DriveLayoutEx.PartitionEntry[pn].StartingOffset, size_to_clear))
uprintf("Could not zero %S: %s", main_part_name, WindowsErrorString());
DriveLayoutEx.PartitionEntry[pn].PartitionLength.QuadPart = main_part_size_in_sectors * SelectedDrive.SectorSize;
if (partition_style == PARTITION_STYLE_MBR) {
DriveLayoutEx.PartitionEntry[pn].Mbr.BootIndicator = (boot_type != BT_NON_BOOTABLE);
switch (file_system) {
case FS_FAT16:
DriveLayoutEx.PartitionEntry[pn].Mbr.PartitionType = 0x0e; // FAT16 LBA
break;
case FS_NTFS:
case FS_EXFAT:
case FS_UDF:
case FS_REFS:
DriveLayoutEx.PartitionEntry[pn].Mbr.PartitionType = 0x07;
break;
case FS_EXT2:
case FS_EXT3:
case FS_EXT4:
DriveLayoutEx.PartitionEntry[pn].Mbr.PartitionType = 0x83;
break;
case FS_FAT32:
DriveLayoutEx.PartitionEntry[pn].Mbr.PartitionType = 0x0c; // FAT32 LBA
break;
default:
uprintf("Unsupported file system");
return FALSE;
}
} else {
if (write_as_esp)
DriveLayoutEx.PartitionEntry[pn].Gpt.PartitionType = PARTITION_GENERIC_ESP;
else if (IS_EXT(file_system))
DriveLayoutEx.PartitionEntry[pn].Gpt.PartitionType = PARTITION_LINUX_DATA;
else
DriveLayoutEx.PartitionEntry[pn].Gpt.PartitionType = PARTITION_MICROSOFT_DATA;
IGNORE_RETVAL(CoCreateGuid(&DriveLayoutEx.PartitionEntry[pn].Gpt.PartitionId));
wcsncpy(DriveLayoutEx.PartitionEntry[pn].Gpt.Name, main_part_name, ARRAYSIZE(DriveLayoutEx.PartitionEntry[pn].Gpt.Name));
}
SelectedDrive.PartitionOffset[pn] = DriveLayoutEx.PartitionEntry[pn].StartingOffset.QuadPart;
SelectedDrive.PartitionSize[pn] = DriveLayoutEx.PartitionEntry[pn].PartitionLength.QuadPart;
partition_offset[PI_MAIN] = SelectedDrive.PartitionOffset[pn];
pn++;
// Set the optional extra partition
if (extra_partitions) {
// Should end on a track boundary
DriveLayoutEx.PartitionEntry[pn].StartingOffset.QuadPart = DriveLayoutEx.PartitionEntry[pn-1].StartingOffset.QuadPart +
DriveLayoutEx.PartitionEntry[pn-1].PartitionLength.QuadPart;
DriveLayoutEx.PartitionEntry[pn].PartitionLength.QuadPart = (extra_partitions & XP_UEFI_NTFS) ? uefi_ntfs_size :
extra_part_size_in_tracks * bytes_per_track;
uprintf("● Creating %S Partition (offset: %lld, size: %s)", extra_part_name, DriveLayoutEx.PartitionEntry[pn].StartingOffset.QuadPart,
SizeToHumanReadable(DriveLayoutEx.PartitionEntry[pn].PartitionLength.QuadPart, TRUE, FALSE));
SelectedDrive.PartitionOffset[pn] = DriveLayoutEx.PartitionEntry[pn].StartingOffset.QuadPart;
SelectedDrive.PartitionSize[pn] = DriveLayoutEx.PartitionEntry[pn].PartitionLength.QuadPart;
if (extra_partitions & XP_CASPER)
partition_offset[PI_CASPER] = SelectedDrive.PartitionOffset[pn];
else if (extra_partitions & XP_ESP)
partition_offset[PI_ESP] = SelectedDrive.PartitionOffset[pn];
if (partition_style == PARTITION_STYLE_GPT) {
if (extra_partitions & XP_ESP)
DriveLayoutEx.PartitionEntry[pn].Gpt.PartitionType = PARTITION_GENERIC_ESP;
else if (extra_partitions & XP_CASPER)
DriveLayoutEx.PartitionEntry[pn].Gpt.PartitionType = PARTITION_LINUX_DATA;
else
DriveLayoutEx.PartitionEntry[pn].Gpt.PartitionType = PARTITION_MICROSOFT_DATA;
if (extra_partitions & XP_UEFI_NTFS) {
// Build the DriveLayoutEx table
for (i = 0; i < pi; i++) {
uprintf("● Creating %S%s (offset: %lld, size: %s)", SelectedDrive.Partition[i].Name,
(wcsstr(SelectedDrive.Partition[i].Name, L"Partition") == NULL) ? " Partition" : "",
SelectedDrive.Partition[i].Offset,
SizeToHumanReadable(SelectedDrive.Partition[i].Size, TRUE, FALSE));
// Zero the first sectors of the partition to avoid file system caching issues
if (!ClearPartition(hDrive, SelectedDrive.Partition[i].Offset,
(DWORD)MIN(size_to_clear, SelectedDrive.Partition[i].Size)))
uprintf("Could not zero %S: %s", SelectedDrive.Partition[i].Name, WindowsErrorString());
DriveLayoutEx.PartitionEntry[i].PartitionStyle = partition_style;
DriveLayoutEx.PartitionEntry[i].StartingOffset.QuadPart = SelectedDrive.Partition[i].Offset;
DriveLayoutEx.PartitionEntry[i].PartitionLength.QuadPart = SelectedDrive.Partition[i].Size;
DriveLayoutEx.PartitionEntry[i].PartitionNumber = i + 1;
DriveLayoutEx.PartitionEntry[i].RewritePartition = TRUE;
if (partition_style == PARTITION_STYLE_MBR) {
if (i == mi) {
DriveLayoutEx.PartitionEntry[i].Mbr.BootIndicator = (boot_type != BT_NON_BOOTABLE);
switch (file_system) {
case FS_FAT16:
DriveLayoutEx.PartitionEntry[i].Mbr.PartitionType = 0x0e; // FAT16 LBA
break;
case FS_NTFS:
case FS_EXFAT:
case FS_UDF:
case FS_REFS:
DriveLayoutEx.PartitionEntry[i].Mbr.PartitionType = 0x07;
break;
case FS_EXT2:
case FS_EXT3:
case FS_EXT4:
DriveLayoutEx.PartitionEntry[i].Mbr.PartitionType = 0x83;
break;
case FS_FAT32:
DriveLayoutEx.PartitionEntry[i].Mbr.PartitionType = 0x0c; // FAT32 LBA
break;
default:
uprintf("Unsupported file system");
return FALSE;
}
}
// May override the the type of main partition if write_as_esp is active
if ((wcscmp(SelectedDrive.Partition[i].Name, L"EFI System Partition") == 0) ||
(wcscmp(SelectedDrive.Partition[i].Name, L"UEFI:NTFS") == 0))
DriveLayoutEx.PartitionEntry[i].Mbr.PartitionType = 0xef;
else if (wcscmp(SelectedDrive.Partition[i].Name, L"Linux Persistence") == 0)
DriveLayoutEx.PartitionEntry[i].Mbr.PartitionType = 0x83;
else if (wcscmp(SelectedDrive.Partition[i].Name, L"BIOS Compatibility") == 0)
DriveLayoutEx.PartitionEntry[i].Mbr.PartitionType = RUFUS_EXTRA_PARTITION_TYPE;
} else {
assert(partition_style == PARTITION_STYLE_GPT);
if (wcscmp(SelectedDrive.Partition[i].Name, L"UEFI:NTFS") == 0) {
DriveLayoutEx.PartitionEntry[i].Gpt.PartitionType = PARTITION_GENERIC_ESP;
// Prevent a drive letter from being assigned to the UEFI:NTFS partition
DriveLayoutEx.PartitionEntry[pn].Gpt.Attributes = GPT_BASIC_DATA_ATTRIBUTE_NO_DRIVE_LETTER;
DriveLayoutEx.PartitionEntry[i].Gpt.Attributes = GPT_BASIC_DATA_ATTRIBUTE_NO_DRIVE_LETTER;
#if !defined(_DEBUG)
// Also make the partition read-only for release versions
DriveLayoutEx.PartitionEntry[pn].Gpt.Attributes += GPT_BASIC_DATA_ATTRIBUTE_READ_ONLY;
DriveLayoutEx.PartitionEntry[i].Gpt.Attributes += GPT_BASIC_DATA_ATTRIBUTE_READ_ONLY;
#endif
}
IGNORE_RETVAL(CoCreateGuid(&DriveLayoutEx.PartitionEntry[pn].Gpt.PartitionId));
wcsncpy(DriveLayoutEx.PartitionEntry[pn].Gpt.Name, (extra_partitions & XP_ESP) ? L"EFI System Partition" : extra_part_name,
ARRAYSIZE(DriveLayoutEx.PartitionEntry[pn].Gpt.Name));
} else {
if (extra_partitions & (XP_UEFI_NTFS | XP_ESP)) {
DriveLayoutEx.PartitionEntry[pn].Mbr.PartitionType = 0xef;
} else if (extra_partitions & XP_CASPER) {
DriveLayoutEx.PartitionEntry[pn].Mbr.PartitionType = 0x83;
} else if (extra_partitions & XP_COMPAT) {
DriveLayoutEx.PartitionEntry[pn].Mbr.PartitionType = RUFUS_EXTRA_PARTITION_TYPE;
// Set the one track compatibility partition to be all hidden sectors
DriveLayoutEx.PartitionEntry[pn].Mbr.HiddenSectors = SelectedDrive.SectorsPerTrack;
} else {
assert(FALSE);
}
} else if (wcscmp(SelectedDrive.Partition[i].Name, L"EFI System Partition") == 0)
DriveLayoutEx.PartitionEntry[i].Gpt.PartitionType = PARTITION_GENERIC_ESP;
else if (wcscmp(SelectedDrive.Partition[i].Name, L"Linux Persistence") == 0)
DriveLayoutEx.PartitionEntry[i].Gpt.PartitionType = PARTITION_LINUX_DATA;
else if (wcscmp(SelectedDrive.Partition[i].Name, L"Microsoft Reserved Partition") == 0)
DriveLayoutEx.PartitionEntry[i].Gpt.PartitionType = PARTITION_MICROSOFT_RESERVED;
else
DriveLayoutEx.PartitionEntry[i].Gpt.PartitionType = PARTITION_MICROSOFT_DATA;
IGNORE_RETVAL(CoCreateGuid(&DriveLayoutEx.PartitionEntry[i].Gpt.PartitionId));
wcscpy(DriveLayoutEx.PartitionEntry[i].Gpt.Name, SelectedDrive.Partition[i].Name);
}
// We need to write the UEFI:NTFS partition before we refresh the disk
if (extra_partitions & XP_UEFI_NTFS) {
uprintf("Writing %S data...", extra_part_name);
if (!SetFilePointerEx(hDrive, DriveLayoutEx.PartitionEntry[pn].StartingOffset, NULL, FILE_BEGIN)) {
uprintf("Could not set position");
return FALSE;
}
buffer = GetResource(hMainInstance, MAKEINTRESOURCEA(IDR_UEFI_NTFS), _RT_RCDATA, "uefi-ntfs.img", &bufsize, FALSE);
if (buffer == NULL) {
uprintf("Could not access source image");
return FALSE;
}
if(!WriteFileWithRetry(hDrive, buffer, bufsize, &size, WRITE_RETRIES)) {
uprintf("Write error: %s", WindowsErrorString());
return FALSE;
}
}
pn++;
}
// Initialize the remaining partition data
for (i = 0; i < pn; i++) {
DriveLayoutEx.PartitionEntry[i].PartitionNumber = i + 1;
DriveLayoutEx.PartitionEntry[i].PartitionStyle = partition_style;
DriveLayoutEx.PartitionEntry[i].RewritePartition = TRUE;
// We need to write the UEFI:NTFS partition before we refresh the disk
if (extra_partitions & XP_UEFI_NTFS) {
LARGE_INTEGER li;
uprintf("Writing UEFI:NTFS data...", SelectedDrive.Partition[partition_index[PI_UEFI_NTFS]].Name);
li.QuadPart = SelectedDrive.Partition[partition_index[PI_UEFI_NTFS]].Offset;
if (!SetFilePointerEx(hDrive, li, NULL, FILE_BEGIN)) {
uprintf(" Could not set position");
return FALSE;
}
buffer = GetResource(hMainInstance, MAKEINTRESOURCEA(IDR_UEFI_NTFS), _RT_RCDATA,
"uefi-ntfs.img", &bufsize, FALSE);
if (buffer == NULL) {
uprintf(" Could not access source image");
return FALSE;
}
if(!WriteFileWithRetry(hDrive, buffer, bufsize, &size, WRITE_RETRIES)) {
uprintf(" Write error: %s", WindowsErrorString());
return FALSE;
}
}
switch (partition_style) {
@ -2550,7 +2525,7 @@ BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL m
CreateDisk.Gpt.MaxPartitionCount = MAX_PARTITIONS;
DriveLayoutEx.PartitionStyle = PARTITION_STYLE_GPT;
DriveLayoutEx.PartitionCount = pn;
DriveLayoutEx.PartitionCount = pi;
// At the very least, a GPT disk has 34 reserved sectors at the beginning and 33 at the end.
DriveLayoutEx.Type.Gpt.StartingUsableOffset.QuadPart = 34 * SelectedDrive.SectorSize;
DriveLayoutEx.Type.Gpt.UsableLength.QuadPart = SelectedDrive.DiskSize - (34+33) * SelectedDrive.SectorSize;
@ -2561,8 +2536,7 @@ BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL m
// If you don't call IOCTL_DISK_CREATE_DISK, the IOCTL_DISK_SET_DRIVE_LAYOUT_EX call will fail
size = sizeof(CreateDisk);
r = DeviceIoControl(hDrive, IOCTL_DISK_CREATE_DISK, (BYTE*)&CreateDisk, size, NULL, 0, &size, NULL);
if (!r) {
if (!DeviceIoControl(hDrive, IOCTL_DISK_CREATE_DISK, (BYTE*)&CreateDisk, size, NULL, 0, &size, NULL)) {
uprintf("Could not reset disk: %s", WindowsErrorString());
return FALSE;
}
@ -2570,9 +2544,9 @@ BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL m
// "The goggles, they do nothing!"
RefreshDriveLayout(hDrive);
size = sizeof(DriveLayoutEx) - ((partition_style == PARTITION_STYLE_GPT)?((4-pn)*sizeof(PARTITION_INFORMATION_EX)):0);
r = DeviceIoControl(hDrive, IOCTL_DISK_SET_DRIVE_LAYOUT_EX, (BYTE*)&DriveLayoutEx, size, NULL, 0, &size, NULL);
if (!r) {
size = sizeof(DriveLayoutEx) - ((partition_style == PARTITION_STYLE_GPT) ?
((4 - pi) * sizeof(PARTITION_INFORMATION_EX)) : 0);
if (!DeviceIoControl(hDrive, IOCTL_DISK_SET_DRIVE_LAYOUT_EX, (BYTE*)&DriveLayoutEx, size, NULL, 0, &size, NULL)) {
uprintf("Could not set drive layout: %s", WindowsErrorString());
return FALSE;
}
@ -2635,5 +2609,44 @@ const char* GetGPTPartitionType(const GUID* guid)
{
int i;
for (i = 0; (i < ARRAYSIZE(gpt_type)) && !CompareGUID(guid, gpt_type[i].guid); i++);
return (i < ARRAYSIZE(gpt_type)) ? gpt_type[i].name : GuidToString(guid);
return (i < ARRAYSIZE(gpt_type)) ? gpt_type[i].name : GuidToString(guid, TRUE);
}
/*
* Detect Microsoft Dev Drives, which are VHDs consisting of a small MSR followed by a large
* (50 GB or more) ReFS partition. See https://learn.microsoft.com/en-us/windows/dev-drive/.
* NB: Despite the option being proposed, I have *NOT* been able to create MBR-based Dev Drives.
*/
BOOL IsMsDevDrive(DWORD DriveIndex)
{
BOOL r, ret = FALSE;
DWORD size = 0;
HANDLE hPhysical = INVALID_HANDLE_VALUE;
BYTE layout[4096] = { 0 };
PDRIVE_LAYOUT_INFORMATION_EX DriveLayout = (PDRIVE_LAYOUT_INFORMATION_EX)(void*)layout;
hPhysical = GetPhysicalHandle(DriveIndex, FALSE, FALSE, TRUE);
if (hPhysical == INVALID_HANDLE_VALUE)
goto out;
r = DeviceIoControl(hPhysical, IOCTL_DISK_GET_DRIVE_LAYOUT_EX,
NULL, 0, layout, sizeof(layout), &size, NULL);
if (!r || size <= 0)
goto out;
if (DriveLayout->PartitionStyle != PARTITION_STYLE_GPT)
goto out;
if (DriveLayout->PartitionCount != 2)
goto out;
if (!CompareGUID(&DriveLayout->PartitionEntry[0].Gpt.PartitionType, &PARTITION_MICROSOFT_RESERVED))
goto out;
if (!CompareGUID(&DriveLayout->PartitionEntry[1].Gpt.PartitionType, &PARTITION_MICROSOFT_DATA))
goto out;
if (DriveLayout->PartitionEntry[1].PartitionLength.QuadPart < 20 * GB)
goto out;
ret = (strcmp(GetFsName(hPhysical, DriveLayout->PartitionEntry[1].StartingOffset), "ReFS") == 0);
out:
safe_closehandle(hPhysical);
return ret;
}

View File

@ -1,7 +1,7 @@
/*
* Rufus: The Reliable USB Formatting Utility
* Drive access function calls
* Copyright © 2011-2022 Pete Batard <pete@akeo.ie>
* Copyright © 2011-2024 Pete Batard <pete@akeo.ie>
*
* 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
@ -36,12 +36,13 @@
#define XP_ESP 0x02
#define XP_UEFI_NTFS 0x04
#define XP_COMPAT 0x08
#define XP_CASPER 0x10
#define XP_PERSISTENCE 0x10
#define PI_MAIN 0
#define PI_ESP 1
#define PI_CASPER 2
#define PI_MAX 3
#define PI_UEFI_NTFS 3
#define PI_MAX 4
// The following should match VDS_FSOF_FLAGS as much as possible
#define FP_FORCE 0x00000001
@ -57,7 +58,7 @@
#define VDS_RESCAN_REFRESH 0x00000001
#define VDS_RESCAN_REENUMERATE 0x00000002
#define VDS_SET_ERROR(hr) do { if (hr != S_OK) { SetLastError(hr); FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_GEN_FAILURE; } } while(0)
#define VDS_SET_ERROR(hr) do { if (hr != S_OK) { SetLastError((DWORD)hr); FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_GEN_FAILURE; } } while(0)
#if !defined(__MINGW32__)
typedef enum _FSINFOCLASS {
@ -362,8 +363,11 @@ typedef struct {
MEDIA_TYPE MediaType;
int PartitionStyle;
int nPartitions; // number of partitions we actually care about
uint64_t PartitionOffset[MAX_PARTITIONS];
uint64_t PartitionSize[MAX_PARTITIONS];
struct {
wchar_t Name[36];
uint64_t Offset;
uint64_t Size;
} Partition[MAX_PARTITIONS];
int FSType;
char proposed_label[16];
BOOL has_protective_mbr;
@ -374,7 +378,7 @@ typedef struct {
} ClusterSize[FS_MAX];
} RUFUS_DRIVE_INFO;
extern RUFUS_DRIVE_INFO SelectedDrive;
extern uint64_t partition_offset[PI_MAX];
extern int partition_index[PI_MAX];
BOOL SetAutoMount(BOOL enable);
BOOL GetAutoMount(BOOL* enabled);
@ -396,7 +400,7 @@ UINT GetDriveTypeFromIndex(DWORD DriveIndex);
char GetUnusedDriveLetter(void);
BOOL IsDriveLetterInUse(const char drive_letter);
char RemoveDriveLetters(DWORD DriveIndex, BOOL bUseLast, BOOL bSilent);
BOOL GetDriveLabel(DWORD DriveIndex, char* letter, char** label);
BOOL GetDriveLabel(DWORD DriveIndex, char* letters, char** label, BOOL bSilent);
uint64_t GetDriveSize(DWORD DriveIndex);
BOOL IsMediaPresent(DWORD DriveIndex);
BOOL AnalyzeMBR(HANDLE hPhysicalDrive, const char* TargetName, BOOL bSilent);
@ -421,3 +425,4 @@ BOOL RefreshLayout(DWORD DriveIndex);
BOOL GetOpticalMedia(IMG_SAVE* img_save);
uint64_t GetEspOffset(DWORD DriveIndex);
BOOL ToggleEsp(DWORD DriveIndex, uint64_t PartitionOffset);
BOOL IsMsDevDrive(DWORD DriveIndex);

View File

@ -1,7 +1,7 @@
/*
* Rufus: The Reliable USB Formatting Utility
* Formatting function calls
* Copyright © 2011-2023 Pete Batard <pete@akeo.ie>
* Copyright © 2011-2024 Pete Batard <pete@akeo.ie>
*
* 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
@ -36,6 +36,7 @@
#endif
#include "rufus.h"
#include "format.h"
#include "missing.h"
#include "resource.h"
#include "settings.h"
@ -73,7 +74,7 @@ extern const int nb_steps[FS_MAX];
extern uint32_t dur_mins, dur_secs;
extern uint32_t wim_nb_files, wim_proc_files, wim_extra_files;
extern BOOL force_large_fat32, enable_ntfs_compression, lock_drive, zero_drive, fast_zeroing, enable_file_indexing;
extern BOOL write_as_image, use_vds, write_as_esp, is_vds_available;
extern BOOL write_as_image, use_vds, write_as_esp, is_vds_available, has_ffu_support;
uint8_t *grub2_buf = NULL, *sec_buf = NULL;
long grub2_len;
@ -971,7 +972,7 @@ static BOOL WriteSBR(HANDLE hPhysicalDrive)
}
// Ensure that we have sufficient space for the SBR
max_size = (DWORD)SelectedDrive.PartitionOffset[0];
max_size = (DWORD)SelectedDrive.Partition[0].Offset;
if (br_size + size > max_size) {
uprintf(" SBR size is too large - You may need to uncheck 'Add fixes for old BIOSes'.");
if (sub_type == BT_MAX)
@ -1154,6 +1155,7 @@ static BOOL WriteDrive(HANDLE hPhysicalDrive, BOOL bZeroDrive)
int64_t bled_ret;
uint8_t* buffer = NULL;
uint32_t zero_data, *cmp_buffer = NULL;
char* vhd_path = NULL;
int throttle_fast_zeroing = 0, read_bufnum = 0, proc_bufnum = 1;
if (SelectedDrive.SectorSize < 512) {
@ -1273,7 +1275,7 @@ static BOOL WriteDrive(HANDLE hPhysicalDrive, BOOL bZeroDrive)
if (i > WRITE_RETRIES)
goto out;
}
} else if (img_report.compression_type != BLED_COMPRESSION_NONE) {
} else if (img_report.compression_type != BLED_COMPRESSION_NONE && img_report.compression_type < BLED_COMPRESSION_MAX) {
uprintf("Writing compressed image:");
hSourceImage = CreateFileU(image_path, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
@ -1310,8 +1312,17 @@ static BOOL WriteDrive(HANDLE hPhysicalDrive, BOOL bZeroDrive)
goto out;
}
} else {
hSourceImage = CreateFileAsync(image_path, GENERIC_READ, FILE_SHARE_READ,
OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN);
assert(img_report.compression_type != IMG_COMPRESSION_FFU);
// VHD/VHDX require mounting the image first
if (img_report.compression_type == IMG_COMPRESSION_VHD ||
img_report.compression_type == IMG_COMPRESSION_VHDX) {
vhd_path = VhdMountImage(image_path);
if (vhd_path == NULL)
goto out;
}
hSourceImage = CreateFileAsync(vhd_path != NULL ? vhd_path : image_path, GENERIC_READ,
FILE_SHARE_READ, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN);
if (hSourceImage == NULL) {
uprintf("Could not open image '%s': %s", image_path, WindowsErrorString());
FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | ERROR_OPEN_FAILED;
@ -1397,10 +1408,12 @@ static BOOL WriteDrive(HANDLE hPhysicalDrive, BOOL bZeroDrive)
RefreshDriveLayout(hPhysicalDrive);
ret = TRUE;
out:
if (img_report.compression_type != BLED_COMPRESSION_NONE)
if (img_report.compression_type != BLED_COMPRESSION_NONE && img_report.compression_type < BLED_COMPRESSION_MAX)
safe_closehandle(hSourceImage);
else
CloseFileAsync(hSourceImage);
if (vhd_path != NULL)
VhdUnmountImage();
safe_mm_free(buffer);
safe_mm_free(cmp_buffer);
return ret;
@ -1443,22 +1456,32 @@ DWORD WINAPI FormatThread(void* param)
large_drive = (SelectedDrive.DiskSize > (1*TB));
if (large_drive)
uprintf("Notice: Large drive detected (may produce short writes)");
// Find out if we need to add any extra partitions
extra_partitions = 0;
if ((boot_type == BT_IMAGE) && !write_as_image && HAS_PERSISTENCE(img_report) && persistence_size)
extra_partitions |= XP_PERSISTENCE;
// According to Microsoft, every GPT disk (we RUN Windows from) must have an MSR due to not having hidden sectors
// https://learn.microsoft.com/en-us/windows-hardware/manufacture/desktop/windows-and-gpt-faq#disks-that-require-an-msr
if ((windows_to_go) && (target_type == TT_UEFI) && (partition_type == PARTITION_STYLE_GPT))
// According to Microsoft, every GPT disk (we RUN Windows from) must have an MSR due to not having hidden sectors
// https://learn.microsoft.com/en-us/windows-hardware/manufacture/desktop/windows-and-gpt-faq#disks-that-require-an-msr
extra_partitions = XP_ESP | XP_MSR;
else if ( ((fs_type == FS_NTFS) || (fs_type == FS_EXFAT)) &&
((boot_type == BT_UEFI_NTFS) || ((boot_type == BT_IMAGE) && IS_EFI_BOOTABLE(img_report) &&
((target_type == TT_UEFI) || (windows_to_go) || (allow_dual_uefi_bios) || (img_report.has_4GB_file)))) )
extra_partitions = XP_UEFI_NTFS;
else if ((boot_type == BT_IMAGE) && !write_as_image && HAS_PERSISTENCE(img_report) && persistence_size)
extra_partitions = XP_CASPER;
else if (IsChecked(IDC_OLD_BIOS_FIXES))
extra_partitions = XP_COMPAT;
extra_partitions |= XP_ESP | XP_MSR;
// If we have a bootable image with UEFI bootloaders and the target file system is NTFS or exFAT
// or the UEFI:NTFS option is selected, we add the UEFI:NTFS partition...
else if (((boot_type == BT_IMAGE) && IS_EFI_BOOTABLE(img_report)) && ((fs_type == FS_NTFS) || (fs_type == FS_EXFAT)) ||
(boot_type == BT_UEFI_NTFS)) {
extra_partitions |= XP_UEFI_NTFS;
// ...but only if we're not dealing with a Windows image in installer mode with target
// system set to BIOS and without dual BIOS+UEFI boot enabled.
if ((boot_type == BT_IMAGE) && HAS_BOOTMGR_BIOS(img_report) && (!windows_to_go) &&
(target_type == TT_BIOS) && (!allow_dual_uefi_bios))
extra_partitions &= ~XP_UEFI_NTFS;
}
if (IsChecked(IDC_OLD_BIOS_FIXES))
extra_partitions |= XP_COMPAT;
// On pre 1703 platforms (and even on later ones), anything with ext2/ext3 doesn't sit
// too well with Windows. Same with ESPs. Relaxing our locking rules seems to help...
if ((extra_partitions & (XP_ESP | XP_CASPER)) || IS_EXT(fs_type))
if ((extra_partitions & (XP_ESP | XP_PERSISTENCE)) || IS_EXT(fs_type))
actual_lock_drive = FALSE;
// Windows 11 is a lot more proactive in locking ESPs and MSRs than previous versions
// were, meaning that we also can't lock the drive without incurring errors...
@ -1627,7 +1650,25 @@ DWORD WINAPI FormatThread(void* param)
// Write an image file
if ((boot_type == BT_IMAGE) && write_as_image) {
WriteDrive(hPhysicalDrive, FALSE);
// Special case for FFU images
if (img_report.compression_type == IMG_COMPRESSION_FFU) {
char cmd[MAX_PATH + 128], *physical = NULL;
// Should have been filtered out beforehand
assert(has_ffu_support);
safe_unlockclose(hPhysicalDrive);
physical = GetPhysicalName(SelectedDrive.DeviceNumber);
static_sprintf(cmd, "dism /Apply-Ffu /ApplyDrive:%s /ImageFile:\"%s\"", physical, image_path);
safe_free(physical);
uprintf("Running command: '%s", cmd);
cr = RunCommandWithProgress(cmd, sysnative_dir, TRUE, MSG_261);
if (cr != 0 && !IS_ERROR(FormatStatus)) {
SetLastError(cr);
uprintf("Failed to apply FFU image: %s", WindowsErrorString());
FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_WINDOWS) | SCODE_CODE(cr);
}
} else {
WriteDrive(hPhysicalDrive, FALSE);
}
goto out;
}
@ -1678,13 +1719,13 @@ DWORD WINAPI FormatThread(void* param)
Sleep(200);
if (write_as_esp || write_as_ext) {
// Can't format ESPs or ext2/ext3 partitions unless we mount them ourselves
volume_name = AltMountVolume(DriveIndex, partition_offset[PI_MAIN], FALSE);
volume_name = AltMountVolume(DriveIndex, SelectedDrive.Partition[partition_index[PI_MAIN]].Offset, FALSE);
if (volume_name == NULL) {
FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | APPERR(ERROR_CANT_ASSIGN_LETTER);
goto out;
}
} else {
if (!WaitForLogical(DriveIndex, partition_offset[PI_MAIN])) {
if (!WaitForLogical(DriveIndex, SelectedDrive.Partition[partition_index[PI_MAIN]].Offset)) {
uprintf("Logical drive was not found - aborting");
if (!IS_ERROR(FormatStatus))
FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | ERROR_TIMEOUT;
@ -1695,12 +1736,12 @@ DWORD WINAPI FormatThread(void* param)
// Format Casper partition if required. Do it before we format anything with
// a file system that Windows will recognize, to avoid concurrent access.
if (extra_partitions & XP_CASPER) {
if (extra_partitions & XP_PERSISTENCE) {
uint32_t ext_version = ReadSetting32(SETTING_USE_EXT_VERSION);
if ((ext_version < 2) || (ext_version > 4))
ext_version = 3;
uprintf("Using %s-like method to enable persistence", img_report.uses_casper ? "Ubuntu" : "Debian");
if (!FormatPartition(DriveIndex, partition_offset[PI_CASPER], 0, FS_EXT2 + (ext_version - 2),
if (!FormatPartition(DriveIndex, SelectedDrive.Partition[partition_index[PI_CASPER]].Offset, 0, FS_EXT2 + (ext_version - 2),
img_report.uses_casper ? "casper-rw" : "persistence",
(img_report.uses_casper ? 0 : FP_CREATE_PERSISTENCE_CONF) |
(IsChecked(IDC_QUICK_FORMAT) ? FP_QUICK : 0))) {
@ -1725,7 +1766,7 @@ DWORD WINAPI FormatThread(void* param)
if (write_as_esp)
Flags |= FP_LARGE_FAT32;
ret = FormatPartition(DriveIndex, partition_offset[PI_MAIN], ClusterSize, fs_type, label, Flags);
ret = FormatPartition(DriveIndex, SelectedDrive.Partition[partition_index[PI_MAIN]].Offset, ClusterSize, fs_type, label, Flags);
if (!ret) {
// Error will be set by FormatPartition() in FormatStatus
uprintf("Format error: %s", StrError(FormatStatus, TRUE));
@ -1758,7 +1799,7 @@ DWORD WINAPI FormatThread(void* param)
// Try to continue
CHECK_FOR_USER_CANCEL;
volume_name = GetLogicalName(DriveIndex, partition_offset[PI_MAIN], TRUE, TRUE);
volume_name = GetLogicalName(DriveIndex, SelectedDrive.Partition[partition_index[PI_MAIN]].Offset, TRUE, TRUE);
if (volume_name == NULL) {
uprintf("Could not get volume name");
FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | ERROR_NO_VOLUME_ID;
@ -1816,7 +1857,7 @@ DWORD WINAPI FormatThread(void* param)
} else {
// We still have a lock, which we need to modify the volume boot record
// => no need to reacquire the lock...
hLogicalVolume = GetLogicalHandle(DriveIndex, partition_offset[PI_MAIN], FALSE, TRUE, FALSE);
hLogicalVolume = GetLogicalHandle(DriveIndex, SelectedDrive.Partition[partition_index[PI_MAIN]].Offset, FALSE, TRUE, FALSE);
if ((hLogicalVolume == INVALID_HANDLE_VALUE) || (hLogicalVolume == NULL)) {
uprintf("Could not re-mount volume for partition boot record access");
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_OPEN_FAILED;
@ -1967,7 +2008,7 @@ out:
}
}
if (IS_ERROR(FormatStatus)) {
volume_name = GetLogicalName(DriveIndex, partition_offset[PI_MAIN], TRUE, TRUE);
volume_name = GetLogicalName(DriveIndex, SelectedDrive.Partition[partition_index[PI_MAIN]].Offset, TRUE, TRUE);
if (volume_name != NULL) {
if (MountVolume(drive_name, volume_name))
uprintf("Re-mounted volume as %c: after error", toupper(drive_name[0]));

View File

@ -1,7 +1,7 @@
/*
* Rufus: The Reliable USB Formatting Utility
* Formatting function calls
* Copyright © 2011-2020 Pete Batard <pete@akeo.ie>
* Copyright © 2011-2023 Pete Batard <pete@akeo.ie>
*
* 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
@ -111,6 +111,10 @@ typedef BOOLEAN (WINAPI* EnableVolumeCompression_t)(
ULONG CompressionFlags // FILE_SYSTEM_PROP_FLAG
);
#define IMG_COMPRESSION_FFU (BLED_COMPRESSION_MAX)
#define IMG_COMPRESSION_VHD (BLED_COMPRESSION_MAX + 1)
#define IMG_COMPRESSION_VHDX (BLED_COMPRESSION_MAX + 2)
BOOL WritePBR(HANDLE hLogicalDrive);
BOOL FormatLargeFAT32(DWORD DriveIndex, uint64_t PartitionOffset, DWORD ClusterSize, LPCSTR FSName, LPCSTR Label, DWORD Flags);
BOOL FormatExtFs(DWORD DriveIndex, uint64_t PartitionOffset, DWORD BlockSize, LPCSTR FSName, LPCSTR Label, DWORD Flags);

View File

@ -175,6 +175,7 @@ BOOL FormatLargeFAT32(DWORD DriveIndex, uint64_t PartitionOffset, DWORD ClusterS
DWORD BytesPerSect = 0;
DWORD SectorsPerCluster = 0;
DWORD TotalSectors = 0;
DWORD AlignSectors = 0;
DWORD SystemAreaSize = 0;
DWORD UserAreaSize = 0;
ULONGLONG qTotalSectors = 0;
@ -295,7 +296,6 @@ BOOL FormatLargeFAT32(DWORD DriveIndex, uint64_t PartitionOffset, DWORD ClusterS
SectorsPerCluster = ClusterSize / BytesPerSect;
pFAT32BootSect->bSecPerClus = (BYTE)SectorsPerCluster;
pFAT32BootSect->wRsvdSecCnt = (WORD)ReservedSectCount;
pFAT32BootSect->bNumFATs = (BYTE)NumFATs;
pFAT32BootSect->wRootEntCnt = 0;
pFAT32BootSect->wTotSec16 = 0;
@ -310,6 +310,13 @@ BOOL FormatLargeFAT32(DWORD DriveIndex, uint64_t PartitionOffset, DWORD ClusterS
FatSize = GetFATSizeSectors(pFAT32BootSect->dTotSec32, pFAT32BootSect->wRsvdSecCnt,
pFAT32BootSect->bSecPerClus, pFAT32BootSect->bNumFATs, BytesPerSect);
// Update reserved sector count so that the start of data region is aligned to a MB boundary
SystemAreaSize = ReservedSectCount + NumFATs * FatSize;
AlignSectors = (1 * MB) / BytesPerSect;
SystemAreaSize = (SystemAreaSize + AlignSectors - 1) / AlignSectors * AlignSectors;
ReservedSectCount = SystemAreaSize - NumFATs * FatSize;
pFAT32BootSect->wRsvdSecCnt = (WORD)ReservedSectCount;
pFAT32BootSect->dFATSz32 = FatSize;
pFAT32BootSect->wExtFlags = 0;
pFAT32BootSect->wFSVer = 0;

View File

@ -2119,8 +2119,10 @@ BOOL IsFileInDB(const char* path)
int IsBootloaderRevoked(const char* path)
{
version_t* ver;
uint32_t i;
uint8_t hash[SHA256_HASHSIZE];
if (!PE256File(path, hash))
return -1;
for (i = 0; i < ARRAYSIZE(pe256dbx); i += SHA256_HASHSIZE)
@ -2129,6 +2131,12 @@ int IsBootloaderRevoked(const char* path)
for (i = 0; i < pe256ssp_size * SHA256_HASHSIZE; i += SHA256_HASHSIZE)
if (memcmp(hash, &pe256ssp[i], SHA256_HASHSIZE) == 0)
return 2;
ver = GetExecutableVersion(path);
// Blanket filter for Windows 10 1607 (excluded) to Windows 10 20H1 (excluded)
// TODO: Revoke all bootloaders prior to 2023.05 once Microsoft does
// uprintf("Found UEFI bootloader version: %d.%d.%d.%d", ver->Major, ver->Minor, ver->Micro, ver->Nano);
if (ver != NULL && ver->Major == 10 && ver->Minor == 0 && ver->Micro > 14393 && ver->Micro < 19041)
return 3;
return 0;
}

396
src/iso.c
View File

@ -1,7 +1,7 @@
/*
* Rufus: The Reliable USB Formatting Utility
* ISO file extraction
* Copyright © 2011-2023 Pete Batard <pete@akeo.ie>
* Copyright © 2011-2024 Pete Batard <pete@akeo.ie>
* Based on libcdio's iso & udf samples:
* Copyright © 2003-2014 Rocky Bernstein <rocky@gnu.org>
*
@ -55,7 +55,6 @@
// How often should we update the progress bar (in 2K blocks) as updating
// the progress bar for every block will bring extraction to a crawl
#define PROGRESS_THRESHOLD 128
#define FOUR_GIGABYTES 4294967296LL
// Needed for UDF symbolic link testing
#define S_IFLNK 0xA000
@ -108,7 +107,7 @@ static const char* grub_dirname[] = { "/boot/grub/i386-pc", "/boot/grub2/i386-pc
static const char* grub_cfg[] = { "grub.cfg", "loopback.cfg" };
static const char* menu_cfg = "menu.cfg";
// NB: Do not alter the order of the array below without validating hardcoded indexes in check_iso_props
static const char* syslinux_cfg[] = { "isolinux.cfg", "syslinux.cfg", "extlinux.conf", "txt.cfg" };
static const char* syslinux_cfg[] = { "isolinux.cfg", "syslinux.cfg", "extlinux.conf", "txt.cfg", "live.cfg" };
static const char* isolinux_bin[] = { "isolinux.bin", "boot.bin" };
static const char* pe_dirname[] = { "/i386", "/amd64", "/minint" };
static const char* pe_file[] = { "ntdetect.com", "setupldr.bin", "txtsetup.sif" };
@ -123,7 +122,7 @@ static const char* stupid_antivirus = " NOTE: This is usually caused by a poorl
const char* old_c32_name[NB_OLD_C32] = OLD_C32_NAMES;
static const int64_t old_c32_threshold[NB_OLD_C32] = OLD_C32_THRESHOLD;
static uint8_t joliet_level = 0;
static uint64_t total_blocks, nb_blocks;
static uint64_t total_blocks, extra_blocks, nb_blocks;
static BOOL scan_only = FALSE;
static StrArray config_path, isolinux_path, modified_path;
static char symlinked_syslinux[MAX_PATH];
@ -243,6 +242,15 @@ static BOOL check_iso_props(const char* psz_dirname, int64_t file_length, const
img_report.has_bootmgr = TRUE;
}
if (safe_stricmp(psz_basename, bootmgr_efi_name) == 0) {
// We may extract the bootloaders for revocation validation later but
// to do so, since we're working with case sensitive file systems, we
// must store all found UEFI bootloader paths with the right case.
for (j = 0; j < ARRAYSIZE(img_report.efi_boot_path); j++) {
if (img_report.efi_boot_path[j][0] == 0) {
static_strcpy(img_report.efi_boot_path[j], psz_fullpath);
break;
}
}
img_report.has_efi |= 1;
img_report.has_bootmgr_efi = TRUE;
}
@ -273,9 +281,27 @@ static BOOL check_iso_props(const char* psz_dirname, int64_t file_length, const
// Check for the EFI boot entries
if (safe_stricmp(psz_dirname, efi_dirname) == 0) {
for (i = 0; i < ARRAYSIZE(efi_bootname); i++)
if (safe_stricmp(psz_basename, efi_bootname[i]) == 0)
for (i = 0; i < ARRAYSIZE(efi_bootname); i++) {
if (safe_stricmp(psz_basename, efi_bootname[i]) == 0) {
img_report.has_efi |= (2 << i); // start at 2 since "bootmgr.efi" is bit 0
for (j = 0; j < ARRAYSIZE(img_report.efi_boot_path); j++) {
if (img_report.efi_boot_path[j][0] == 0) {
static_strcpy(img_report.efi_boot_path[j], psz_fullpath);
break;
}
}
}
}
// Linux Mint Edge 21.2/Mint 21.3 have an invalid /EFI/boot/bootx64.efi
// because it's a symbolic link to a file that does not exist on the media.
// This is originally due to a Debian bug that was fixed in:
// https://salsa.debian.org/live-team/live-build/-/commit/5bff71fea2dd54adcd6c428d3f1981734079a2f7
// Because of this, if we detect a small bootx64.efi file, we assert that it's a
// broken link and try to extract a "good" version from the El-Torito image.
if ((safe_stricmp(psz_basename, efi_bootname[2]) == 0) && (file_length < 256)) {
img_report.has_efi |= 0x4000;
static_strcpy(img_report.efi_img_path, "[BOOT]/1-Boot-NoEmul.img");
}
}
if (psz_dirname != NULL) {
@ -295,24 +321,24 @@ static BOOL check_iso_props(const char* psz_dirname, int64_t file_length, const
}
// Check for PE (XP) specific files in "/i386", "/amd64" or "/minint"
for (i=0; i<ARRAYSIZE(pe_dirname); i++)
for (i = 0; i < ARRAYSIZE(pe_dirname); i++)
if (safe_stricmp(psz_dirname, pe_dirname[i]) == 0)
for (j=0; j<ARRAYSIZE(pe_file); j++)
if (safe_stricmp(psz_basename, pe_file[j]) == 0)
img_report.winpe |= (1<<j)<<(ARRAYSIZE(pe_dirname)*i);
for (i=0; i<ARRAYSIZE(isolinux_bin); i++) {
for (i = 0; i < ARRAYSIZE(isolinux_bin); i++) {
if (safe_stricmp(psz_basename, isolinux_bin[i]) == 0) {
// Maintain a list of all the isolinux.bin files found
StrArrayAdd(&isolinux_path, psz_fullpath, TRUE);
}
}
for (i=0; i<NB_OLD_C32; i++) {
for (i = 0; i < NB_OLD_C32; i++) {
if (props->is_old_c32[i])
img_report.has_old_c32[i] = TRUE;
}
if (file_length >= FOUR_GIGABYTES)
if (file_length >= 4 * GB)
img_report.has_4GB_file = TRUE;
// Compute projected size needed (NB: ISO_BLOCKSIZE = UDF_BLOCKSIZE)
if (file_length != 0)
@ -354,6 +380,11 @@ static void fix_config(const char* psz_fullpath, const char* psz_path, const cha
// Ubuntu 23.04 uses GRUB only with the above and does not use "maybe-ubiquity"
uprintf(" Added 'persistent' kernel option");
modified = TRUE;
} else if (replace_in_token_data(src, props->is_grub_cfg ? "linux" : "append",
"boot=casper", "boot=casper persistent", TRUE) != NULL) {
// Linux Mint uses boot=casper.
uprintf(" Added 'persistent' kernel option");
modified = TRUE;
} else if (replace_in_token_data(src, props->is_grub_cfg ? "linux" : "append",
"boot=live", "boot=live persistence", TRUE) != NULL) {
// Debian & derivatives are assumed to use 'boot=live' in
@ -378,9 +409,10 @@ static void fix_config(const char* psz_fullpath, const char* psz_path, const cha
//'linux' but '$linux'... and we have to add a workaround for that.
// Then, newer Arch and derivatives added an extra "search --label ..." command
// in their GRUB conf, which we need to cater for in supplement of the kernel line.
// Then Artix called in and decided they would use a "for kopt ..." loop.
// Finally, we're just shoving the known isolinux/syslinux tokens in there to process
// all config files equally.
static const char* cfg_token[] = { "options", "append", "linux", "linuxefi", "$linux", "search" };
static const char* cfg_token[] = { "options", "append", "linux", "linuxefi", "$linux", "search", "for"};
iso_label = replace_char(img_report.label, ' ', "\\x20");
usb_label = replace_char(img_report.usb_label, ' ', "\\x20");
if ((iso_label != NULL) && (usb_label != NULL)) {
@ -448,6 +480,62 @@ static void fix_config(const char* psz_fullpath, const char* psz_path, const cha
free(src);
}
// This updates the MD5SUMS/md5sum.txt file that some distros (Ubuntu, Mint...)
// use to validate the media. Because we may alter some of the validated files
// to add persistence and whatnot, we need to alter the MD5 list as a result.
// The format of the file is expected to always be "<MD5SUM> <FILE_PATH>" on
// individual lines.
static void update_md5sum(void)
{
BOOL display_header = TRUE;
intptr_t pos;
uint32_t i, j, size, md5_size;
uint8_t* buf = NULL, sum[16];
char md5_path[64], * md5_data = NULL, * str_pos;
if (!img_report.has_md5sum)
goto out;
assert(img_report.has_md5sum <= ARRAYSIZE(md5sum_name));
if (img_report.has_md5sum > ARRAYSIZE(md5sum_name))
goto out;
static_sprintf(md5_path, "%s\\%s", psz_extract_dir, md5sum_name[img_report.has_md5sum - 1]);
md5_size = read_file(md5_path, (uint8_t**)&md5_data);
if (md5_size == 0)
goto out;
for (i = 0; i < modified_path.Index; i++) {
str_pos = strstr(md5_data, &modified_path.String[i][2]);
if (str_pos == NULL)
// File is not listed in md5 sums
continue;
if (display_header) {
uprintf("Updating %s:", md5_path);
display_header = FALSE;
}
uprintf("● %s", &modified_path.String[i][2]);
pos = str_pos - md5_data;
size = read_file(modified_path.String[i], &buf);
if (size == 0)
continue;
HashBuffer(HASH_MD5, buf, size, sum);
free(buf);
while ((pos > 0) && (md5_data[pos - 1] != '\n'))
pos--;
for (j = 0; j < 16; j++) {
md5_data[pos + 2 * j] = ((sum[j] >> 4) < 10) ? ('0' + (sum[j] >> 4)) : ('a' - 0xa + (sum[j] >> 4));
md5_data[pos + 2 * j + 1] = ((sum[j] & 15) < 10) ? ('0' + (sum[j] & 15)) : ('a' - 0xa + (sum[j] & 15));
}
}
write_file(md5_path, md5_data, md5_size);
free(md5_data);
out:
StrArrayDestroy(&modified_path);
}
static void print_extracted_file(char* psz_fullpath, uint64_t file_length)
{
size_t nul_pos;
@ -628,71 +716,16 @@ out:
return 1;
}
// This updates the MD5SUMS/md5sum.txt file that some distros (Ubuntu, Mint...)
// use to validate the media. Because we may alter some of the validated files
// to add persistence and whatnot, we need to alter the MD5 list as a result.
// The format of the file is expected to always be "<MD5SUM> <FILE_PATH>" on
// individual lines.
static void update_md5sum(void)
{
BOOL display_header = TRUE;
intptr_t pos;
uint32_t i, j, size, md5_size;
uint8_t *buf = NULL, sum[16];
char md5_path[64], *md5_data = NULL, *str_pos;
if (!img_report.has_md5sum)
goto out;
assert(img_report.has_md5sum <= ARRAYSIZE(md5sum_name));
if (img_report.has_md5sum > ARRAYSIZE(md5sum_name))
goto out;
static_sprintf(md5_path, "%s\\%s", psz_extract_dir, md5sum_name[img_report.has_md5sum - 1]);
md5_size = read_file(md5_path, (uint8_t**)&md5_data);
if (md5_size == 0)
goto out;
for (i = 0; i < modified_path.Index; i++) {
str_pos = strstr(md5_data, &modified_path.String[i][2]);
if (str_pos == NULL)
// File is not listed in md5 sums
continue;
if (display_header) {
uprintf("Updating %s:", md5_path);
display_header = FALSE;
}
uprintf("● %s", &modified_path.String[i][2]);
pos = str_pos - md5_data;
size = read_file(modified_path.String[i], &buf);
if (size == 0)
continue;
HashBuffer(HASH_MD5, buf, size, sum);
free(buf);
while ((pos > 0) && (md5_data[pos - 1] != '\n'))
pos--;
for (j = 0; j < 16; j++) {
md5_data[pos + 2 * j] = ((sum[j] >> 4) < 10) ? ('0' + (sum[j] >> 4)) : ('a' - 0xa + (sum[j] >> 4));
md5_data[pos + 2 * j + 1] = ((sum[j] & 15) < 10) ? ('0' + (sum[j] & 15)) : ('a' - 0xa + (sum[j] & 15));
}
}
write_file(md5_path, md5_data, md5_size);
free(md5_data);
out:
StrArrayDestroy(&modified_path);
}
// Returns 0 on success, >0 on error, <0 to ignore current dir
static int iso_extract_files(iso9660_t* p_iso, const char *psz_path)
{
HANDLE file_handle = NULL;
DWORD buf_size, wr_size, err;
EXTRACT_PROPS props;
BOOL is_symlink, is_identical, free_p_statbuf = FALSE;
BOOL is_symlink, is_identical, create_file, free_p_statbuf = FALSE;
int length, r = 1;
char tmp[128], psz_fullpath[MAX_PATH], *psz_basename = NULL, *psz_sanpath = NULL;
char psz_fullpath[MAX_PATH], *psz_basename = NULL, *psz_sanpath = NULL;
char tmp[128], target_path[256];
const char *psz_iso_name = &psz_fullpath[strlen(psz_extract_dir)];
unsigned char buf[ISO_BLOCKSIZE];
CdioListNode_t* p_entnode;
@ -776,6 +809,21 @@ static int iso_extract_files(iso9660_t* p_iso, const char *psz_path)
} else {
file_length = p_statbuf->total_size;
if (check_iso_props(psz_path, file_length, psz_basename, psz_fullpath, &props)) {
if (is_symlink && (file_length == 0)) {
// Add symlink duplicated files to total_size at scantime
if ((strcmp(psz_path, "/firmware") == 0)) {
static_sprintf(target_path, "%s/%s", psz_path, p_statbuf->rr.psz_symlink);
iso9660_stat_t* p_statbuf2 = iso9660_ifs_stat_translate(p_iso, target_path);
if (p_statbuf2 != NULL) {
extra_blocks += (p_statbuf2->total_size + ISO_BLOCKSIZE - 1) / ISO_BLOCKSIZE;
iso9660_stat_free(p_statbuf2);
}
} else if ((strcmp(p_statbuf->filename, "live") == 0) &&
(strcmp(p_statbuf->rr.psz_symlink, "casper") == 0)) {
// Mint LMDE requires working symbolic links and therefore requires the use of NTFS
img_report.needs_ntfs = TRUE;
}
}
continue;
}
if (!is_symlink)
@ -795,8 +843,26 @@ static int iso_extract_files(iso9660_t* p_iso, const char *psz_path)
psz_sanpath = sanitize_filename(psz_fullpath, &is_identical);
if (!is_identical)
uprintf(" File name sanitized to '%s'", psz_sanpath);
create_file = TRUE;
if (is_symlink) {
if (file_length == 0) {
if (fs_type == FS_NTFS) {
// Replicate symlinks if NTFS is being used
static_sprintf(target_path, "%s/%s", psz_path, p_statbuf->rr.psz_symlink);
iso9660_stat_t* p_statbuf2 = iso9660_ifs_stat_translate(p_iso, target_path);
if (p_statbuf2 != NULL) {
to_windows_path(psz_fullpath);
to_windows_path(p_statbuf->rr.psz_symlink);
uprintf("Symlinking: %s%s ➔ %s", psz_fullpath,
(p_statbuf2->type == _STAT_DIR) ? "\\" : "", p_statbuf->rr.psz_symlink);
if (!CreateSymbolicLinkU(psz_fullpath, p_statbuf->rr.psz_symlink,
(p_statbuf2->type == _STAT_DIR) ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0))
uprintf(" Could not create symlink: %s", WindowsErrorString());
to_unix_path(p_statbuf->rr.psz_symlink);
to_unix_path(psz_fullpath);
iso9660_stat_free(p_statbuf2);
create_file = FALSE;
}
} else if (file_length == 0) {
if ((safe_stricmp(p_statbuf->filename, "syslinux") == 0) &&
// Special handling for ISOs that have a syslinux → isolinux symbolic link (e.g. Knoppix)
(safe_stricmp(p_statbuf->rr.psz_symlink, "isolinux") == 0)) {
@ -806,7 +872,6 @@ static int iso_extract_files(iso9660_t* p_iso, const char *psz_path)
} else if (strcmp(psz_path, "/firmware") == 0) {
// Special handling for ISOs that use symlinks for /firmware/ (e.g. Debian non-free)
// TODO: Do we want to do this for all file symlinks?
char target_path[256];
static_sprintf(target_path, "%s/%s", psz_path, p_statbuf->rr.psz_symlink);
p_statbuf = iso9660_ifs_stat_translate(p_iso, target_path);
if (p_statbuf != NULL) {
@ -821,45 +886,58 @@ static int iso_extract_files(iso9660_t* p_iso, const char *psz_path)
goto out;
}
} else {
// TODO: Ideally, we'd want to create a text file that contains the target link
print_extracted_file(psz_fullpath, file_length);
print_extracted_file(psz_fullpath, safe_strlen(p_statbuf->rr.psz_symlink));
uprintf(" Ignoring Rock Ridge symbolic link to '%s'", p_statbuf->rr.psz_symlink);
}
} else {
uuprintf("Unexpected symlink length: %d", file_length);
create_file = FALSE;
}
}
file_handle = CreatePreallocatedFile(psz_sanpath, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, file_length);
if (file_handle == INVALID_HANDLE_VALUE) {
err = GetLastError();
uprintf(" Unable to create file: %s", WindowsErrorString());
if (((err == ERROR_ACCESS_DENIED) || (err == ERROR_INVALID_HANDLE)) &&
(safe_strcmp(&psz_sanpath[3], autorun_name) == 0))
uprintf(stupid_antivirus);
else
goto out;
} else for (i = 0; file_length > 0; i++) {
if (FormatStatus) goto out;
memset(buf, 0, ISO_BLOCKSIZE);
lsn = p_statbuf->lsn + (lsn_t)i;
if (iso9660_iso_seek_read(p_iso, buf, lsn, 1) != ISO_BLOCKSIZE) {
uprintf(" Error reading ISO9660 file %s at LSN %lu",
psz_iso_name, (long unsigned int)lsn);
goto out;
if (create_file) {
file_handle = CreatePreallocatedFile(psz_sanpath, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, file_length);
if (file_handle == INVALID_HANDLE_VALUE) {
err = GetLastError();
uprintf(" Unable to create file: %s", WindowsErrorString());
if (((err == ERROR_ACCESS_DENIED) || (err == ERROR_INVALID_HANDLE)) &&
(safe_strcmp(&psz_sanpath[3], autorun_name) == 0))
uprintf(stupid_antivirus);
else
goto out;
} else if (is_symlink) {
// Create a text file that contains the target link
ISO_BLOCKING(r = WriteFileWithRetry(file_handle, p_statbuf->rr.psz_symlink,
(DWORD)safe_strlen(p_statbuf->rr.psz_symlink), &wr_size, WRITE_RETRIES));
if (!r) {
uprintf(" Error writing file: %s", WindowsErrorString());
goto out;
}
} else for (i = 0; file_length > 0; i++) {
if (FormatStatus) goto out;
memset(buf, 0, ISO_BLOCKSIZE);
lsn = p_statbuf->lsn + (lsn_t)i;
if (iso9660_iso_seek_read(p_iso, buf, lsn, 1) != ISO_BLOCKSIZE) {
uprintf(" Error reading ISO9660 file %s at LSN %lu",
psz_iso_name, (long unsigned int)lsn);
goto out;
}
buf_size = (DWORD)MIN(file_length, ISO_BLOCKSIZE);
ISO_BLOCKING(r = WriteFileWithRetry(file_handle, buf, buf_size, &wr_size, WRITE_RETRIES));
if (!r) {
uprintf(" Error writing file: %s", WindowsErrorString());
goto out;
}
file_length -= ISO_BLOCKSIZE;
if (nb_blocks++ % PROGRESS_THRESHOLD == 0)
UpdateProgressWithInfo(OP_FILE_COPY, MSG_231, nb_blocks, total_blocks +
((fs_type != FS_NTFS) ? extra_blocks : 0));
}
buf_size = (DWORD)MIN(file_length, ISO_BLOCKSIZE);
ISO_BLOCKING(r = WriteFileWithRetry(file_handle, buf, buf_size, &wr_size, WRITE_RETRIES));
if (!r) {
uprintf(" Error writing file: %s", WindowsErrorString());
goto out;
if (preserve_timestamps) {
LPFILETIME ft = to_filetime(mktime(&p_statbuf->tm));
if (!SetFileTime(file_handle, ft, ft, ft))
uprintf(" Could not set timestamp: %s", WindowsErrorString());
}
file_length -= ISO_BLOCKSIZE;
if (nb_blocks++ % PROGRESS_THRESHOLD == 0)
UpdateProgressWithInfo(OP_FILE_COPY, MSG_231, nb_blocks, total_blocks);
}
if (preserve_timestamps) {
LPFILETIME ft = to_filetime(mktime(&p_statbuf->tm));
if (!SetFileTime(file_handle, ft, ft, ft))
uprintf(" Could not set timestamp: %s", WindowsErrorString());
}
if (free_p_statbuf)
iso9660_stat_free(p_statbuf);
@ -989,6 +1067,7 @@ BOOL ExtractISO(const char* src_iso, const char* dest_dir, BOOL scan)
uprintf("ISO analysis:");
SendMessage(hMainDialog, UM_PROGRESS_INIT, PBS_MARQUEE, 0);
total_blocks = 0;
extra_blocks = 0;
has_ldlinux_c32 = FALSE;
// String array of all isolinux/syslinux locations
StrArrayCreate(&config_path, 8);
@ -1071,7 +1150,7 @@ out:
if ((iso9660_ifs_read_pvd(p_iso, &pvd)) && (_stat64U(src_iso, &stat) == 0))
img_report.mismatch_size = (int64_t)(iso9660_get_pvd_space_size(&pvd)) * ISO_BLOCKSIZE - stat.st_size;
// Remove trailing spaces from the label
for (k=(int)safe_strlen(img_report.label)-1; ((k>0)&&(isspaceU(img_report.label[k]))); k--)
for (k = (int)safe_strlen(img_report.label) - 1; ((k > 0) && (isspaceU(img_report.label[k]))); k--)
img_report.label[k] = 0;
// We use the fact that UDF_BLOCKSIZE and ISO_BLOCKSIZE are the same here
img_report.projected_size = total_blocks * ISO_BLOCKSIZE;
@ -1081,9 +1160,9 @@ out:
if (!IsStrArrayEmpty(config_path)) {
// Set the img_report.cfg_path string to maximum length, so that we don't have to
// do a special case for StrArray entry 0.
memset(img_report.cfg_path, '_', sizeof(img_report.cfg_path)-1);
img_report.cfg_path[sizeof(img_report.cfg_path)-1] = 0;
for (i=0; i<config_path.Index; i++) {
memset(img_report.cfg_path, '_', sizeof(img_report.cfg_path) - 1);
img_report.cfg_path[sizeof(img_report.cfg_path) - 1] = 0;
for (i = 0; i < config_path.Index; i++) {
// OpenSuse based Live image have a /syslinux.cfg that doesn't work, so we enforce
// the use of the one in '/boot/[i386|x86_64]/loader/isolinux.cfg' if present.
// Note that, because the openSuse live script are not designed to handle anything but
@ -1105,7 +1184,7 @@ out:
}
uprintf(" Will use '%s' for Syslinux", img_report.cfg_path);
// Extract all of the isolinux.bin files we found to identify their versions
for (i=0; i<isolinux_path.Index; i++) {
for (i = 0; i < isolinux_path.Index; i++) {
char isolinux_tmp[MAX_PATH];
static_sprintf(isolinux_tmp, "%sisolinux.tmp", temp_dir);
size = (size_t)ExtractISOFile(src_iso, isolinux_path.String[i], isolinux_tmp, FILE_ATTRIBUTE_NORMAL);
@ -1132,7 +1211,7 @@ out:
img_report.sl_version_ext, isolinux_path.String[i], SL_MAJOR(sl_version), SL_MINOR(sl_version), ext);
// Workaround for Antergos and other ISOs, that have multiple Syslinux versions.
// Where possible, prefer to the one that resides in the same directory as the config file.
for (j=safe_strlen(img_report.cfg_path); (j>0) && (img_report.cfg_path[j]!='/'); j--);
for (j=safe_strlen(img_report.cfg_path); (j > 0) && (img_report.cfg_path[j] != '/'); j--);
if (safe_strnicmp(img_report.cfg_path, isolinux_path.String[i], j) == 0) {
static_strcpy(img_report.sl_version_ext, ext);
img_report.sl_version = sl_version;
@ -1172,7 +1251,7 @@ out:
ExtractISOFile(src_iso, path, tmp_sif, FILE_ATTRIBUTE_NORMAL);
tmp = get_token_data_file("OsLoadOptions", tmp_sif);
if (tmp != NULL) {
for (i=0; i<strlen(tmp); i++)
for (i = 0; i < strlen(tmp); i++)
tmp[i] = (char)tolower(tmp[i]);
uprintf(" Checking txtsetup.sif:\n OsLoadOptions = %s", tmp);
img_report.uses_minint = (strstr(tmp, "/minint") != NULL);
@ -1213,8 +1292,16 @@ out:
SendMessage(hMainDialog, UM_PROGRESS_EXIT, 0, 0);
} else {
// Solus and other ISOs only provide EFI boot files in a FAT efi.img
if (img_report.has_efi == 0x8000)
// Also work around ISOs that have a borked symbolic link for bootx64.efi.
// See https://github.com/linuxmint/linuxmint/issues/622.
if (img_report.has_efi & 0xc000) {
if (img_report.has_efi & 0x4000) {
uprintf("Broken UEFI bootloader detected - Applying workaround:");
static_sprintf(path, "%s\\EFI\\boot\\bootx64.efi", dest_dir);
DeleteFileU(path);
}
DumpFatDir(dest_dir, 0);
}
if (HAS_SYSLINUX(img_report)) {
static_sprintf(path, "%s\\syslinux.cfg", dest_dir);
// Create a /syslinux.cfg (if none exists) that points to the existing isolinux cfg
@ -1283,6 +1370,19 @@ out:
// bootmgr might need to be uncompressed: https://github.com/pbatard/rufus/issues/1381
RunCommand("compact /u bootmgr* efi/boot/*.efi", dest_dir, TRUE);
}
// Exception for Slax Syslinux UEFI bootloaders...
// ...that don't appear to work anyway as of slax-64bit-slackware-15.0.3.iso
static_sprintf(path, "%s\\slax\\boot\\EFI", dest_dir);
if (PathFileExistsA(path)) {
char dst_path[16];
static_sprintf(dst_path, "%s\\EFI", dest_dir);
if (!PathFileExistsA(dst_path)) {
if (MoveFileA(path, dst_path))
uprintf("Moved: %s → %s", path, dst_path);
else
uprintf("Could not move %s → %s", path, dst_path, WindowsErrorString());
}
}
update_md5sum();
if (archive_path != NULL) {
uprintf("● Adding files from %s", archive_path);
@ -1386,6 +1486,8 @@ try_iso:
out:
safe_closehandle(file_handle);
if (r == 0)
DeleteFileU(dest_file);
iso9660_stat_free(p_statbuf);
udf_dirent_free(p_udf_root);
udf_dirent_free(p_udf_file);
@ -1650,7 +1752,7 @@ BOOL DumpFatDir(const char* path, int32_t cluster)
}
if (!DumpFatDir(target, dirpos.cluster))
goto out;
} else {
} else if (!PathFileExistsU(target)) {
// Need to figure out if it's a .conf file (Damn you Solus!!)
EXTRACT_PROPS props = { 0 };
size_t len = strlen(name);
@ -1670,7 +1772,7 @@ BOOL DumpFatDir(const char* path, int32_t cluster)
buf = libfat_get_sector(lf_fs, s);
if (buf == NULL)
FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | ERROR_SECTOR_NOT_FOUND;
if (FormatStatus)
if (IS_ERROR(FormatStatus))
goto out;
size = MIN(LIBFAT_SECTOR_SIZE, diritem.size - written);
if (!WriteFileWithRetry(handle, buf, size, &size, WRITE_RETRIES) ||
@ -1710,68 +1812,8 @@ out:
return ret;
}
static char physical_path[128] = "";
static HANDLE mounted_handle = INVALID_HANDLE_VALUE;
char* MountISO(const char* path)
{
VIRTUAL_STORAGE_TYPE vtype = { 1, VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT };
ATTACH_VIRTUAL_DISK_PARAMETERS vparams = { 0 };
DWORD r;
wchar_t wtmp[128];
ULONG size = ARRAYSIZE(wtmp);
wconvert(path);
char* ret = NULL;
if ((mounted_handle != NULL) && (mounted_handle != INVALID_HANDLE_VALUE))
UnMountISO();
r = OpenVirtualDisk(&vtype, wpath, VIRTUAL_DISK_ACCESS_READ | VIRTUAL_DISK_ACCESS_GET_INFO,
OPEN_VIRTUAL_DISK_FLAG_NONE, NULL, &mounted_handle);
if (r != ERROR_SUCCESS) {
SetLastError(r);
uprintf("Could not open ISO '%s': %s", path, WindowsErrorString());
goto out;
}
vparams.Version = ATTACH_VIRTUAL_DISK_VERSION_1;
r = AttachVirtualDisk(mounted_handle, NULL, ATTACH_VIRTUAL_DISK_FLAG_READ_ONLY |
ATTACH_VIRTUAL_DISK_FLAG_NO_DRIVE_LETTER, 0, &vparams, NULL);
if (r != ERROR_SUCCESS) {
SetLastError(r);
uprintf("Could not mount ISO '%s': %s", path, WindowsErrorString());
goto out;
}
r = GetVirtualDiskPhysicalPath(mounted_handle, &size, wtmp);
if (r != ERROR_SUCCESS) {
SetLastError(r);
uprintf("Could not obtain physical path for mounted ISO '%s': %s", path, WindowsErrorString());
goto out;
}
wchar_to_utf8_no_alloc(wtmp, physical_path, sizeof(physical_path));
ret = physical_path;
out:
if (ret == NULL)
UnMountISO();
wfree(path);
return ret;
}
void UnMountISO(void)
{
if ((mounted_handle == NULL) || (mounted_handle == INVALID_HANDLE_VALUE))
goto out;
DetachVirtualDisk(mounted_handle, DETACH_VIRTUAL_DISK_FLAG_NONE, 0);
safe_closehandle(mounted_handle);
out:
physical_path[0] = 0;
}
// TODO: If we can't get save to ISO from virtdisk, we might as well drop this
static DWORD WINAPI SaveISOThread(void* param)
static DWORD WINAPI IsoSaveImageThread(void* param)
{
BOOL s;
DWORD rSize, wSize;
@ -1877,7 +1919,7 @@ out:
ExitThread(0);
}
void SaveISO(void)
void IsoSaveImage(void)
{
static IMG_SAVE img_save = { 0 };
char filename[33] = "disc_image.iso";
@ -1908,7 +1950,7 @@ void SaveISO(void)
// Disable all controls except cancel
EnableControls(FALSE, FALSE);
InitProgress(TRUE);
format_thread = CreateThread(NULL, 0, SaveISOThread, &img_save, 0, NULL);
format_thread = CreateThread(NULL, 0, IsoSaveImageThread, &img_save, 0, NULL);
if (format_thread != NULL) {
uprintf("\r\nSave to ISO operation started");
PrintInfo(0, -1);

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2003-2008, 2012-2013, 2017
Copyright (C) 2003-2008, 2012-2013, 2017, 2023-2024
Rocky Bernstein <rocky@gnu.org>
Copyright (C) 2000 Herbert Valerio Riedel <hvr@gnu.org>
@ -27,7 +27,7 @@
* filesystem library; applications include this.
*
* See also the ISO-9660 specification. The freely available European
* equivalant standard is called ECMA-119.
* equivalent standard is called ECMA-119.
*/
@ -78,7 +78,7 @@ typedef char dchar_t; /*! See section 7.4.1 */
program; things are done this way so that in a debugger one can to
refer to the enumeration value names such as in a debugger
expression and get something. With the more common a \#define
mechanism, the name/value assocation is lost at run time.
mechanism, the name/value association is lost at run time.
*/
extern enum iso_enum1_s {
ISO_PVD_SECTOR = 16, /**< Sector of Primary Volume Descriptor. */
@ -93,8 +93,9 @@ extern enum iso_enum1_s {
preparer id. */
MAX_ISOPATHNAME = 255, /**< Maximum number of characters in the
entire ISO 9660 filename. */
ISO_BLOCKSIZE = 2048 /**< Number of bytes in an ISO 9660 block. */
ISO_BLOCKSIZE = 2048, /**< Number of bytes in an ISO 9660 block. */
VIRTUAL_SECTORSIZE = 512 /**< Number of bytes in an El Torito virtual
image sector */
} iso_enums1;
/*! An enumeration for some of the ISO_* \#defines below. This isn't
@ -162,6 +163,7 @@ extern enum iso_vd_enum_s {
extern const char ISO_STANDARD_ID[sizeof("CD001")-1];
#define ISO_STANDARD_ID "CD001"
#define EL_TORITO_ID "EL TORITO SPECIFICATION\0\0\0\0\0\0\0\0\0"
#define CDIO_EXTENT_BLOCKS(size) ((size + (ISO_BLOCKSIZE - 1)) / ISO_BLOCKSIZE)
@ -395,7 +397,7 @@ typedef struct iso9660_pvd_s iso9660_pvd_t;
/*!
\brief ISO-9660 Supplementary Volume Descriptor.
This is used for Joliet Extentions and is almost the same as the
This is used for Joliet Extensions and is almost the same as the
the primary descriptor but two unused fields, "unused1" and "unused3
become "flags and "escape_sequences" respectively.
*/
@ -506,6 +508,37 @@ struct iso9660_svd_s {
typedef struct iso9660_svd_s iso9660_svd_t;
/*!
\brief ISO-9660 Boot Record Volume Descriptor.
*/
struct iso9660_brvd_s {
uint8_t type; /**< ISO_VD_BOOT_RECORD - 0 */
char id[5]; /**< ISO_STANDARD_ID "CD001" */
uint8_t version; /**< value 1 for El Torito */
char system_id[ISO_MAX_SYSTEM_ID]; /**< Boot system ID */
uint8_t unused1[32]; /**< unused - value 0 */
uint32_t boot_catalog_sector; /**< first sector of boot catalog */
uint8_t unused2[1973]; /**< Unused - value 0 */
} GNUC_PACKED;
typedef struct iso9660_brvd_s iso9660_brvd_t;
/*!
\brief ISO-9660 Boot Record Volume Descriptor.
*/
struct iso9660_br_s {
uint8_t boot_id; /**< Boot indicator - 0x88 */
uint8_t media_type; /**< Boot media type - 0 for no emul. */
uint16_t load_seg; /**< Load segment for x86 */
uint8_t system_type; /**< System type - 0 for x86 */
uint8_t unused1;
uint16_t num_sectors; /**< Virtual sectors count of the image */
uint32_t image_lsn; /**< Start address of the image */
uint8_t unused2[20];
} GNUC_PACKED;
typedef struct iso9660_br_s iso9660_br_t;
PRAGMA_END_PACKED
/*! \brief A data type for a list of ISO9660
@ -550,7 +583,7 @@ struct iso9660_stat_s { /* big endian!! */
/* Multi-extent aware size, in bytes.
It is guaranteed that the bytes are stored as gapless string in a
continguous sequence of blocks. I.e. they can be read sequentially
contiguous sequence of blocks. I.e. they can be read sequentially
starting at iso9660_stat_s.lsn.
Data files which do not fulfil this promise cause a warning message
and are not represented by this type of struct.
@ -582,7 +615,8 @@ extern enum iso_extension_enum_s {
ISO_EXTENSION_JOLIET_LEVEL2 = 0x02,
ISO_EXTENSION_JOLIET_LEVEL3 = 0x04,
ISO_EXTENSION_ROCK_RIDGE = 0x08,
ISO_EXTENSION_HIGH_SIERRA = 0x10
ISO_EXTENSION_HIGH_SIERRA = 0x10,
ISO_EXTENSION_EL_TORITO = 0x20
} iso_extension_enums;
@ -638,7 +672,7 @@ typedef struct _iso9660_s iso9660_t;
contained in a file format that libiso9660 doesn't know natively
(or knows imperfectly.)
Some tolerence allowed for positioning the ISO 9660 image. We scan
Some tolerance allowed for positioning the ISO 9660 image. We scan
for STANDARD_ID and use that to set the eventual offset to adjust
by (as long as that is <= i_fuzz).
@ -650,7 +684,7 @@ typedef struct _iso9660_s iso9660_t;
uint16_t i_fuzz);
/*!
Open an ISO 9660 image for reading with some tolerence for positioning
Open an ISO 9660 image for reading with some tolerance for positioning
of the ISO9660 image. We scan for ISO_STANDARD_ID and use that to set
the eventual offset to adjust by (as long as that is <= i_fuzz).
@ -766,7 +800,7 @@ typedef struct _iso9660_s iso9660_t;
tm will reported in GMT.
*/
bool iso9660_get_dtime (const iso9660_dtime_t *idr_date, bool b_localtime,
/*out*/ struct tm *tm);
/*out*/ struct tm *p_tm);
/*!
@ -857,7 +891,7 @@ typedef struct _iso9660_s iso9660_t;
/*!
Take psz_path and a version number and turn that into a ISO-9660
pathname. (That's just the pathname followd by ";" and the version
pathname. (That's just the pathname followed by ";" and the version
number. For example, mydir/file.ext -> MYDIR/FILE.EXT;1 for version
1. The resulting ISO-9660 pathname is returned.
*/
@ -1202,7 +1236,7 @@ lsn_t iso9660_get_dir_extent(const iso9660_dir_t *p_idr);
@param p_iso the ISO-9660 file image to get data from
@param u_file_limit the maximimum number of (non-rock-ridge) files
@param u_file_limit the maximum number of (non-rock-ridge) files
to consider before giving up and returning "dunno".
"dunno" can also be returned if there was some error encountered
@ -1278,7 +1312,7 @@ lsn_t iso9660_get_dir_extent(const iso9660_dir_t *p_idr);
void iso9660_set_evd (void *pd);
/*!
Return true if ISO 9660 image has extended attrributes (XA).
Return true if ISO 9660 image has extended attributes (XA).
*/
bool iso9660_ifs_is_xa (const iso9660_t * p_iso);

View File

@ -105,6 +105,12 @@ _cdio_memdup (const void *mem, size_t count);
char *
_cdio_strdup_upper (const char str[]);
int
_cdio_stricmp(const char str1[], const char str2[]);
int
_cdio_strnicmp(const char str1[], const char str2[], size_t count);
/*! Duplicate path and make it platform compliant. Typically needed for
MinGW/MSYS where a "/c/..." path must be translated to "c:/..." for
use with fopen(), etc. Returned string must be freed by the caller

View File

@ -142,6 +142,35 @@ _cdio_strdup_upper (const char str[])
return new_str;
}
int
_cdio_stricmp (const char str1[], const char str2[])
{
if (str1 && str2) {
int c1, c2;
do {
c1 = tolower((unsigned char)*str1++);
c2 = tolower((unsigned char)*str2++);
} while (c1 == c2 && c1 != '\0');
return c1 - c2;
} else return (str1 != str2);
}
int
_cdio_strnicmp(const char str1[], const char str2[], size_t count)
{
if (str1 && str2) {
int c1 = 0, c2 = 0;
size_t i;
for (i = 0; i < count; i++) {
c1 = tolower((unsigned char)*str1++);
c2 = tolower((unsigned char)*str2++);
if (c1 != c2 || c1 == '\0')
break;
}
return c1 - c2;
} else return (str1 != str2);
}
/* Convert MinGW/MSYS paths that start in "/c/..." to "c:/..."
so that they can be used with fopen(), stat(), etc.
Returned string must be freed by the caller using cdio_free().*/

View File

@ -1,6 +1,7 @@
/*
Copyright (C) 2003-2008, 2011-2015, 2017 Rocky Bernstein <rocky@gnu.org>
Copyright (C) 2018, 2020 Pete Batard <pete@akeo.ie>
Copyright (C) 2003-2008, 2011-2015, 2017, 2024
Rocky Bernstein <rocky@gnu.org>
Copyright (C) 2018, 2020, 2024 Pete Batard <pete@akeo.ie>
Copyright (C) 2018 Thomas Schmitt <scdbackup@gmx.net>
Copyright (C) 2001 Herbert Valerio Riedel <hvr@gnu.org>
@ -59,6 +60,9 @@
#include "_cdio_stdio.h"
#include "cdio_private.h"
/* Maximum number of El-Torito boot images we keep an index for */
#define MAX_BOOT_IMAGES 8
/** Implementation of iso9660_t type */
struct _iso9660_s {
cdio_header_t header; /**< Internal header - MUST come first. */
@ -83,6 +87,11 @@ struct _iso9660_s {
be CDIO_CD_FRAMESIZE_RAW (2352) or
M2RAW_SECTOR_SIZE (2336).
*/
struct {
uint32_t lsn; /**< Start LSN of an El-Torito bootable image */
uint32_t num_sectors; /**< Number of virtual sectors occupied by the
bootable image */
} boot_img[MAX_BOOT_IMAGES];
int i_fuzzy_offset; /**< Adjustment in bytes to make ISO_STANDARD_ID
("CD001") come out as ISO_PVD_SECTOR
(frame 16). Normally this should be 0
@ -505,7 +514,8 @@ iso9660_ifs_read_superblock (iso9660_t *p_iso,
iso_extension_mask_t iso_extension_mask)
{
iso9660_svd_t p_svd; /* Secondary volume descriptor. */
int i;
iso9660_brvd_t* p_brvd = (iso9660_brvd_t*)&p_svd; /* Boot record volume descriptor. */
int i, j, k;
if (!p_iso || !iso9660_ifs_read_pvd(p_iso, &(p_iso->pvd)))
return false;
@ -516,6 +526,50 @@ iso9660_ifs_read_superblock (iso9660_t *p_iso,
for (i=1; (0 != iso9660_iso_seek_read (p_iso, &p_svd, ISO_PVD_SECTOR+i, 1)); i++) {
if (ISO_VD_END == from_711(p_svd.type) ) /* Last SVD */
break;
if (iso_extension_mask & ISO_EXTENSION_EL_TORITO) {
/* Check for an El-Torito boot volume descriptor */
if (ISO_VD_BOOT_RECORD == from_711(p_svd.type) &&
(memcmp(p_brvd->system_id, EL_TORITO_ID, ISO_MAX_SYSTEM_ID) == 0)) {
/* Perform basic parsing of boot entries to fill an image table */
iso9660_br_t br[ISO_BLOCKSIZE / sizeof(iso9660_br_t)];
if (iso9660_iso_seek_read(p_iso, &br, p_brvd->boot_catalog_sector, 1) ==
ISO_BLOCKSIZE) {
for (j = 0, k = 0;
j < (ISO_BLOCKSIZE / sizeof(iso9660_br_t)) && k < MAX_BOOT_IMAGES;
j++) {
if (br[j].boot_id == 0x88 && br[j].media_type == 0) {
p_iso->boot_img[k].lsn = uint32_from_le(br[j].image_lsn);
p_iso->boot_img[k++].num_sectors = uint16_from_le(br[j].num_sectors);
}
}
/* Special case for non specs-compliant images that do follow the UEFI */
/* specs and that use size 0 or 1 for images larger than 0xffff virtual */
/* sectors, in which case the image runs to the end of the volume (per */
/* UEFI specs) or to the next LSN (as seen with some software). */
cdio_assert(ISO_BLOCKSIZE / VIRTUAL_SECTORSIZE == 4);
for (j = 0; j < MAX_BOOT_IMAGES; j++) {
uint32_t next_lsn = from_733(p_iso->pvd.volume_space_size);
if (p_iso->boot_img[j].lsn == 0)
continue;
/* Find the closest LSN after the one from this image */
cdio_assert(p_iso->boot_img[j].lsn < next_lsn);
for (k = 0; k < MAX_BOOT_IMAGES; k++) {
if (p_iso->boot_img[k].lsn > p_iso->boot_img[j].lsn &&
p_iso->boot_img[k].lsn < next_lsn)
next_lsn = p_iso->boot_img[k].lsn;
}
/* If the image has a sector size of 0 or 1 and theres' more than */
/* 0xffff sectors to the next LSN, assume it needs expansion. */
if (p_iso->boot_img[j].num_sectors <= 1 &&
(next_lsn - p_iso->boot_img[j].lsn) >= 0x4000) {
p_iso->boot_img[j].num_sectors =
(next_lsn - p_iso->boot_img[j].lsn) * 4;
cdio_warn("Auto-expanding the size of %d-Boot-NoEmul.img", j);
}
}
}
}
}
if ( ISO_VD_SUPPLEMENTARY == from_711(p_svd.type) ) {
/* We're only interested in Joliet => make sure the SVD isn't overwritten */
if (p_iso->u_joliet_level == 0)
@ -798,7 +852,7 @@ _iso9660_is_rock_ridge_enabled(void* p_image)
/*!
Convert a directory record name to a 0-terminated string.
One of parameters alloc_result and cpy_result should be non-NULL to take
the result.
the result.
*/
static bool
_iso9660_recname_to_cstring(const char *src, size_t src_len,
@ -1236,7 +1290,7 @@ _fs_iso_stat_traverse (iso9660_t *p_iso, const iso9660_stat_t *_root,
{
unsigned offset = 0;
uint8_t *_dirbuf = NULL;
uint32_t blocks;
uint32_t blocks;
int ret, cmp;
iso9660_stat_t *p_stat = NULL;
iso9660_dir_t *p_iso9660_dir = NULL;
@ -1441,6 +1495,34 @@ iso9660_fs_stat_translate (CdIo_t *p_cdio, const char psz_path[])
iso9660_stat_t *
iso9660_ifs_stat_translate (iso9660_t *p_iso, const char psz_path[])
{
/* Special case for virtual El-Torito boot images ('/[BOOT]/#-Boot-NoEmul.img') */
if (psz_path && p_iso && p_iso->boot_img[0].lsn != 0) {
/* Work on a path without leading slash */
const char* path = (psz_path[0] == '/') ? &psz_path[1] : psz_path;
if ((_cdio_strnicmp(path, "[BOOT]/", 7) == 0) &&
(_cdio_stricmp(&path[8], "-Boot-NoEmul.img") == 0)) {
int index = path[7] - '0';
iso9660_stat_t* p_stat;
if (strlen(path) < 24)
return NULL;
cdio_assert(MAX_BOOT_IMAGES <= 10);
if ((path[7] < '0') || (path[7] > '0' + MAX_BOOT_IMAGES - 1))
return NULL;
if (p_iso->boot_img[index].lsn == 0 || p_iso->boot_img[index].num_sectors == 0)
return NULL;
p_stat = calloc(1, sizeof(iso9660_stat_t) + strlen(path));
if (!p_stat) {
cdio_warn("Couldn't calloc(1, %d)", (int)sizeof(iso9660_stat_t));
return NULL;
}
p_stat->lsn = p_iso->boot_img[index].lsn;
p_stat->total_size = p_iso->boot_img[index].num_sectors * VIRTUAL_SECTORSIZE;
p_stat->type = _STAT_FILE;
strcpy(p_stat->filename, path);
return p_stat;
}
}
return fs_stat_translate(p_iso, (stat_root_t *) _ifs_stat_root,
(stat_traverse_t *) _fs_iso_stat_traverse,
psz_path);
@ -1576,6 +1658,7 @@ iso9660_fs_readdir (CdIo_t *p_cdio, const char psz_path[])
CdioISO9660FileList_t *
iso9660_ifs_readdir (iso9660_t *p_iso, const char psz_path[])
{
int i;
iso9660_dir_t *p_iso9660_dir;
iso9660_stat_t *p_iso9660_stat = NULL;
iso9660_stat_t *p_stat;
@ -1583,6 +1666,30 @@ iso9660_ifs_readdir (iso9660_t *p_iso, const char psz_path[])
if (!p_iso) return NULL;
if (!psz_path) return NULL;
/* List the virtual El-Torito images */
if (p_iso->boot_img[0].lsn != 0) {
const char* path = (psz_path[0] == '/') ? &psz_path[1] : psz_path;
if (_cdio_strnicmp(path, "[BOOT]", 6) == 0 && (path[6] == '\0' || path[6] == '/')) {
CdioList_t* retval = _cdio_list_new();
for (i = 0; i < MAX_BOOT_IMAGES && p_iso->boot_img[i].lsn != 0; i++) {
p_iso9660_stat = calloc(1, sizeof(iso9660_stat_t) + 18);
if (!p_iso9660_stat) {
cdio_warn("Couldn't calloc(1, %d)", (int)sizeof(iso9660_stat_t) + 18);
break;
}
strcpy(p_iso9660_stat->filename, "#-Boot-NoEmul.img");
p_iso9660_stat->filename[0] = '0' + i;
p_iso9660_stat->type = _STAT_FILE;
p_iso9660_stat->lsn = p_iso->boot_img[i].lsn;
p_iso9660_stat->total_size = p_iso->boot_img[i].num_sectors * VIRTUAL_SECTORSIZE;
iso9660_get_ltime(&p_iso->pvd.creation_date, &p_iso9660_stat->tm);
_cdio_list_append(retval, p_iso9660_stat);
p_iso9660_stat = NULL;
}
return retval;
}
}
p_stat = iso9660_ifs_stat (p_iso, psz_path);
if (!p_stat) return NULL;
@ -1600,6 +1707,21 @@ iso9660_ifs_readdir (iso9660_t *p_iso, const char psz_path[])
const size_t dirbuf_len = blocks * ISO_BLOCKSIZE;
bool skip_following_extents = false;
/* Add the virtual El-Torito "[BOOT]" directory to root */
if (p_iso->boot_img[0].lsn != 0) {
if (psz_path[0] == '\0' || (psz_path[0] == '/' && psz_path[1] == '\0')) {
p_iso9660_stat = calloc(1, sizeof(iso9660_stat_t) + 7);
if (p_iso9660_stat) {
strcpy(p_iso9660_stat->filename, "[BOOT]");
p_iso9660_stat->type = _STAT_DIR;
p_iso9660_stat->lsn = ISO_PVD_SECTOR + 1;
iso9660_get_ltime(&p_iso->pvd.creation_date, &p_iso9660_stat->tm);
_cdio_list_append(retval, p_iso9660_stat);
p_iso9660_stat = NULL;
}
}
}
if (!dirbuf_len)
{
cdio_warn("Invalid directory buffer sector size %u", blocks);

View File

@ -1,7 +1,7 @@
/*
* Rufus: The Reliable USB Formatting Utility
* Licensing Data
* Copyright © 2011-2015 Pete Batard <pete@akeo.ie>
* Copyright © 2011-2023 Pete Batard <pete@akeo.ie>
*
* 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
@ -89,8 +89,8 @@ const char* additional_copyrights =
"https://www.codeguru.com/forum/showthread.php?p=1951973\\line\n"
"Public Domain\\line\n"
"\\line\n"
"Handle search & process enumeration from Process Hacker by wj32 & dmex:\\line\n"
"https://processhacker.sourceforge.io/\\line\n"
"Handle search & process enumeration from System Informer by wj32 & dmex:\\line\n"
"https://systeminformer.sourceforge.io/\\line\n"
"GNU General Public License (GPL) v3 or later\\line\n"
"\\line\n"
"Decompression support from BusyBox/Bled:\\line\n"

View File

@ -12,7 +12,7 @@ cat > cmd.sed <<\_EOF
1i /*\
* Rufus: The Reliable USB Formatting Utility\
* Localization tables - autogenerated from resource.h\
* Copyright © 2013-2023 Pete Batard <pete@akeo.ie>\
* Copyright © 2013-2024 Pete Batard <pete@akeo.ie>\
*\
* 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\

View File

@ -1,7 +1,7 @@
/*
* Rufus: The Reliable USB Formatting Utility
* Constants and defines missing from various toolchains
* Copyright © 2016-2022 Pete Batard <pete@akeo.ie>
* Copyright © 2016-2024 Pete Batard <pete@akeo.ie>
*
* 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
@ -31,6 +31,9 @@
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
#endif
#define LO_ALIGN_X_TO_Y(x, y) (((x) / (y)) * (y))
#define HI_ALIGN_X_TO_Y(x, y) ((((x) + (y) - 1) / (y)) * (y))
#if defined(__GNUC__)
#define ALIGNED(m) __attribute__ ((__aligned__(m)))
#elif defined(_MSC_VER)

View File

@ -1233,6 +1233,16 @@ static __inline BOOL MoveFileExU(const char* lpExistingFileName, const char* lpN
return ret;
}
static __inline BOOL CreateSymbolicLinkU(const char* lpSymlinkFileName, const char* lpTargetFileName, DWORD dwFlags)
{
wconvert(lpSymlinkFileName);
wconvert(lpTargetFileName);
BOOL ret = CreateSymbolicLinkW(wlpSymlinkFileName, wlpTargetFileName, dwFlags);
wfree(lpTargetFileName);
wfree(lpSymlinkFileName);
return ret;
}
// The following expects PropertyBuffer to contain a single Unicode string
static __inline BOOL SetupDiGetDeviceRegistryPropertyU(HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData,
DWORD Property, PDWORD PropertyRegDataType, PBYTE PropertyBuffer, DWORD PropertyBufferSize, PDWORD RequiredSize)

210
src/net.c
View File

@ -1,7 +1,7 @@
/*
* Rufus: The Reliable USB Formatting Utility
* Networking functionality (web file download, check for update, etc.)
* Copyright © 2012-2023 Pete Batard <pete@akeo.ie>
* Copyright © 2012-2024 Pete Batard <pete@akeo.ie>
*
* 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
@ -62,177 +62,6 @@ static const char* request_headers = "Accept-Encoding: gzip, deflate";
#define INetworkListManager_get_IsConnectedToInternet INetworkListManager_IsConnectedToInternet
#endif
/*
* FormatMessage does not handle internet errors
* https://docs.microsoft.com/en-us/windows/desktop/wininet/wininet-errors
*/
const char* WinInetErrorString(void)
{
static char error_string[256];
DWORD size = sizeof(error_string);
PF_TYPE_DECL(WINAPI, BOOL, InternetGetLastResponseInfoA, (LPDWORD, LPSTR, LPDWORD));
PF_INIT(InternetGetLastResponseInfoA, WinInet);
error_code = HRESULT_CODE(GetLastError());
if ((error_code < INTERNET_ERROR_BASE) || (error_code > INTERNET_ERROR_LAST))
return WindowsErrorString();
switch(error_code) {
case ERROR_INTERNET_OUT_OF_HANDLES:
return "No more handles could be generated at this time.";
case ERROR_INTERNET_TIMEOUT:
return "The request has timed out.";
case ERROR_INTERNET_INTERNAL_ERROR:
return "An internal error has occurred.";
case ERROR_INTERNET_INVALID_URL:
return "The URL is invalid.";
case ERROR_INTERNET_UNRECOGNIZED_SCHEME:
return "The URL scheme could not be recognized or is not supported.";
case ERROR_INTERNET_NAME_NOT_RESOLVED:
return "The server name could not be resolved.";
case ERROR_INTERNET_PROTOCOL_NOT_FOUND:
return "The requested protocol could not be located.";
case ERROR_INTERNET_INVALID_OPTION:
return "A request specified an invalid option value.";
case ERROR_INTERNET_BAD_OPTION_LENGTH:
return "The length of an option supplied is incorrect for the type of option specified.";
case ERROR_INTERNET_OPTION_NOT_SETTABLE:
return "The request option cannot be set, only queried.";
case ERROR_INTERNET_SHUTDOWN:
return "The Win32 Internet function support is being shut down or unloaded.";
case ERROR_INTERNET_INCORRECT_USER_NAME:
return "The request to connect and log on to an FTP server could not be completed because the supplied user name is incorrect.";
case ERROR_INTERNET_INCORRECT_PASSWORD:
return "The request to connect and log on to an FTP server could not be completed because the supplied password is incorrect.";
case ERROR_INTERNET_LOGIN_FAILURE:
return "The request to connect to and log on to an FTP server failed.";
case ERROR_INTERNET_INVALID_OPERATION:
return "The requested operation is invalid.";
case ERROR_INTERNET_OPERATION_CANCELLED:
return "The operation was cancelled, usually because the handle on which the request was operating was closed before the operation completed.";
case ERROR_INTERNET_INCORRECT_HANDLE_TYPE:
return "The type of handle supplied is incorrect for this operation.";
case ERROR_INTERNET_INCORRECT_HANDLE_STATE:
return "The requested operation cannot be carried out because the handle supplied is not in the correct state.";
case ERROR_INTERNET_NOT_PROXY_REQUEST:
return "The request cannot be made via a proxy.";
case ERROR_INTERNET_REGISTRY_VALUE_NOT_FOUND:
return "A required registry value could not be located.";
case ERROR_INTERNET_BAD_REGISTRY_PARAMETER:
return "A required registry value was located but is an incorrect type or has an invalid value.";
case ERROR_INTERNET_NO_DIRECT_ACCESS:
return "Direct network access cannot be made at this time.";
case ERROR_INTERNET_NO_CONTEXT:
return "An asynchronous request could not be made because a zero context value was supplied.";
case ERROR_INTERNET_NO_CALLBACK:
return "An asynchronous request could not be made because a callback function has not been set.";
case ERROR_INTERNET_REQUEST_PENDING:
return "The required operation could not be completed because one or more requests are pending.";
case ERROR_INTERNET_INCORRECT_FORMAT:
return "The format of the request is invalid.";
case ERROR_INTERNET_ITEM_NOT_FOUND:
return "The requested item could not be located.";
case ERROR_INTERNET_CANNOT_CONNECT:
return "The attempt to connect to the server failed.";
case ERROR_INTERNET_CONNECTION_ABORTED:
return "The connection with the server has been terminated.";
case ERROR_INTERNET_CONNECTION_RESET:
return "The connection with the server has been reset.";
case ERROR_INTERNET_FORCE_RETRY:
return "Calls for the Win32 Internet function to redo the request.";
case ERROR_INTERNET_INVALID_PROXY_REQUEST:
return "The request to the proxy was invalid.";
case ERROR_INTERNET_HANDLE_EXISTS:
return "The request failed because the handle already exists.";
case ERROR_INTERNET_SEC_INVALID_CERT:
return "The SSL certificate is invalid.";
case ERROR_INTERNET_SEC_CERT_DATE_INVALID:
return "SSL certificate date that was received from the server is bad. The certificate is expired.";
case ERROR_INTERNET_SEC_CERT_CN_INVALID:
return "SSL certificate common name (host name field) is incorrect.";
case ERROR_INTERNET_SEC_CERT_ERRORS:
return "The SSL certificate contains errors.";
case ERROR_INTERNET_SEC_CERT_NO_REV:
return "The SSL certificate was not revoked.";
case ERROR_INTERNET_SEC_CERT_REV_FAILED:
return "The revocation check of the SSL certificate failed.";
case ERROR_INTERNET_HTTP_TO_HTTPS_ON_REDIR:
return "The application is moving from a non-SSL to an SSL connection because of a redirect.";
case ERROR_INTERNET_HTTPS_TO_HTTP_ON_REDIR:
return "The application is moving from an SSL to an non-SSL connection because of a redirect.";
case ERROR_INTERNET_MIXED_SECURITY:
return "Some of the content being viewed may have come from unsecured servers.";
case ERROR_INTERNET_CHG_POST_IS_NON_SECURE:
return "The application is posting and attempting to change multiple lines of text on a server that is not secure.";
case ERROR_INTERNET_POST_IS_NON_SECURE:
return "The application is posting data to a server that is not secure.";
case ERROR_FTP_TRANSFER_IN_PROGRESS:
return "The requested operation cannot be made on the FTP session handle because an operation is already in progress.";
case ERROR_FTP_DROPPED:
return "The FTP operation was not completed because the session was aborted.";
case ERROR_GOPHER_PROTOCOL_ERROR:
case ERROR_GOPHER_NOT_FILE:
case ERROR_GOPHER_DATA_ERROR:
case ERROR_GOPHER_END_OF_DATA:
case ERROR_GOPHER_INVALID_LOCATOR:
case ERROR_GOPHER_INCORRECT_LOCATOR_TYPE:
case ERROR_GOPHER_NOT_GOPHER_PLUS:
case ERROR_GOPHER_ATTRIBUTE_NOT_FOUND:
case ERROR_GOPHER_UNKNOWN_LOCATOR:
return "Gopher? Really??? What is this, 1994?";
case ERROR_HTTP_HEADER_NOT_FOUND:
return "The requested header could not be located.";
case ERROR_HTTP_DOWNLEVEL_SERVER:
return "The server did not return any headers.";
case ERROR_HTTP_INVALID_SERVER_RESPONSE:
return "The server response could not be parsed.";
case ERROR_HTTP_INVALID_HEADER:
return "The supplied header is invalid.";
case ERROR_HTTP_INVALID_QUERY_REQUEST:
return "The request made to HttpQueryInfo is invalid.";
case ERROR_HTTP_HEADER_ALREADY_EXISTS:
return "The header could not be added because it already exists.";
case ERROR_HTTP_REDIRECT_FAILED:
return "The redirection failed because either the scheme changed or all attempts made to redirect failed.";
case ERROR_INTERNET_SECURITY_CHANNEL_ERROR:
return "This system's SSL library is too old to be able to access this website.";
case ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED:
return "Client Authentication certificate needed";
case ERROR_INTERNET_BAD_AUTO_PROXY_SCRIPT:
return "Bad auto proxy script.";
case ERROR_INTERNET_UNABLE_TO_DOWNLOAD_SCRIPT:
return "Unable to download script.";
case ERROR_INTERNET_NOT_INITIALIZED:
return "Internet has not be initialized.";
case ERROR_INTERNET_UNABLE_TO_CACHE_FILE:
return "Unable to cache the file.";
case ERROR_INTERNET_TCPIP_NOT_INSTALLED:
return "TPC/IP not installed.";
case ERROR_INTERNET_DISCONNECTED:
return "Internet is disconnected.";
case ERROR_INTERNET_SERVER_UNREACHABLE:
return "Server could not be reached.";
case ERROR_INTERNET_PROXY_SERVER_UNREACHABLE:
return "Proxy server could not be reached.";
case ERROR_INTERNET_FAILED_DUETOSECURITYCHECK:
return "A security check prevented internet connection.";
case ERROR_INTERNET_NEED_MSN_SSPI_PKG:
return "This connection requires an MSN Security Support Provider Interface package.";
case ERROR_INTERNET_LOGIN_FAILURE_DISPLAY_ENTITY_BODY:
return "Please ask Microsoft about that one!";
case ERROR_INTERNET_EXTENDED_ERROR:
if (pfInternetGetLastResponseInfoA != NULL) {
pfInternetGetLastResponseInfoA(&error_code, error_string, &size);
return error_string;
}
// fall through
default:
static_sprintf(error_string, "Unknown internet error 0x%08lX", error_code);
return error_string;
}
}
static char* GetShortName(const char* url)
{
static char short_name[128];
@ -393,34 +222,34 @@ uint64_t DownloadToFileOrBufferEx(const char* url, const char* file, const char*
if ( (!pfInternetCrackUrlA(url, (DWORD)safe_strlen(url), 0, &UrlParts))
|| (UrlParts.lpszHostName == NULL) || (UrlParts.lpszUrlPath == NULL)) {
uprintf("Unable to decode URL: %s", WinInetErrorString());
uprintf("Unable to decode URL: %s", WindowsErrorString());
goto out;
}
hostname[sizeof(hostname)-1] = 0;
hSession = GetInternetSession(user_agent, TRUE);
if (hSession == NULL) {
uprintf("Could not open Internet session: %s", WinInetErrorString());
uprintf("Could not open Internet session: %s", WindowsErrorString());
goto out;
}
hConnection = pfInternetConnectA(hSession, UrlParts.lpszHostName, UrlParts.nPort, NULL, NULL, INTERNET_SERVICE_HTTP, 0, (DWORD_PTR)NULL);
if (hConnection == NULL) {
uprintf("Could not connect to server %s:%d: %s", UrlParts.lpszHostName, UrlParts.nPort, WinInetErrorString());
uprintf("Could not connect to server %s:%d: %s", UrlParts.lpszHostName, UrlParts.nPort, WindowsErrorString());
goto out;
}
hRequest = pfHttpOpenRequestA(hConnection, "GET", UrlParts.lpszUrlPath, NULL, NULL, accept_types,
INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP|INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTPS|
INTERNET_FLAG_NO_COOKIES|INTERNET_FLAG_NO_UI|INTERNET_FLAG_NO_CACHE_WRITE|INTERNET_FLAG_HYPERLINK|
INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP | INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTPS |
INTERNET_FLAG_NO_COOKIES | INTERNET_FLAG_NO_UI | INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_HYPERLINK |
((UrlParts.nScheme==INTERNET_SCHEME_HTTPS)?INTERNET_FLAG_SECURE:0), (DWORD_PTR)NULL);
if (hRequest == NULL) {
uprintf("Could not open URL %s: %s", url, WinInetErrorString());
uprintf("Could not open URL %s: %s", url, WindowsErrorString());
goto out;
}
if (!pfHttpSendRequestA(hRequest, request_headers, -1L, NULL, 0)) {
uprintf("Unable to send request: %s", WinInetErrorString());
uprintf("Unable to send request: %s", WindowsErrorString());
goto out;
}
@ -435,7 +264,7 @@ uint64_t DownloadToFileOrBufferEx(const char* url, const char* file, const char*
}
dwSize = sizeof(strsize);
if (!pfHttpQueryInfoA(hRequest, HTTP_QUERY_CONTENT_LENGTH, (LPVOID)strsize, &dwSize, NULL)) {
uprintf("Unable to retrieve file length: %s", WinInetErrorString());
uprintf("Unable to retrieve file length: %s", WindowsErrorString());
goto out;
}
total_size = strtoull(strsize, NULL, 10);
@ -452,7 +281,7 @@ uint64_t DownloadToFileOrBufferEx(const char* url, const char* file, const char*
if (file != NULL) {
hFile = CreateFileU(file, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
uprintf("Unable to create file '%s': %s", short_name, WinInetErrorString());
uprintf("Unable to create file '%s': %s", short_name, WindowsErrorString());
goto out;
}
} else {
@ -479,7 +308,7 @@ uint64_t DownloadToFileOrBufferEx(const char* url, const char* file, const char*
UpdateProgressWithInfo(OP_NOOP, MSG_241, size, total_size);
if (file != NULL) {
if (!WriteFile(hFile, buf, dwDownloaded, &dwWritten, NULL)) {
uprintf("Error writing file '%s': %s", short_name, WinInetErrorString());
uprintf("Error writing file '%s': %s", short_name, WindowsErrorString());
goto out;
} else if (dwDownloaded != dwWritten) {
uprintf("Error writing file '%s': Only %d/%d bytes written", short_name, dwWritten, dwDownloaded);
@ -564,11 +393,11 @@ DWORD DownloadSignedFile(const char* url, const char* file, HWND hProgressDialog
DownloadStatus = 206; // Partial content
hFile = CreateFileU(file, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
uprintf("Unable to create file '%s': %s", PathFindFileNameU(file), WinInetErrorString());
uprintf("Unable to create file '%s': %s", PathFindFileNameU(file), WindowsErrorString());
goto out;
}
if (!WriteFile(hFile, buf, buf_len, &ret, NULL)) {
uprintf("Error writing file '%s': %s", PathFindFileNameU(file), WinInetErrorString());
uprintf("Error writing file '%s': %s", PathFindFileNameU(file), WindowsErrorString());
ret = 0;
goto out;
} else if (ret != buf_len) {
@ -584,7 +413,7 @@ out:
if ((bPromptOnError) && (DownloadStatus != 200)) {
PrintInfo(0, MSG_242);
SetLastError(error_code);
MessageBoxExU(hMainDialog, IS_ERROR(FormatStatus) ? StrError(FormatStatus, FALSE) : WinInetErrorString(),
MessageBoxExU(hMainDialog, IS_ERROR(FormatStatus) ? StrError(FormatStatus, FALSE) : WindowsErrorString(),
lmprintf(MSG_044), MB_OK | MB_ICONERROR | MB_IS_RTL, selected_langid);
}
safe_closehandle(hFile);
@ -758,7 +587,7 @@ static DWORD WINAPI CheckForUpdatesThread(LPVOID param)
INTERNET_FLAG_NO_COOKIES|INTERNET_FLAG_NO_UI|INTERNET_FLAG_NO_CACHE_WRITE|INTERNET_FLAG_HYPERLINK|
((UrlParts.nScheme == INTERNET_SCHEME_HTTPS)?INTERNET_FLAG_SECURE:0), (DWORD_PTR)NULL);
if ((hRequest == NULL) || (!pfHttpSendRequestA(hRequest, request_headers, -1L, NULL, 0))) {
uprintf("Unable to send request: %s", WinInetErrorString());
uprintf("Unable to send request: %s", WindowsErrorString());
goto out;
}
@ -915,7 +744,7 @@ static DWORD WINAPI DownloadISOThread(LPVOID param)
// thinking that Rufus is doing something malicious...
IGNORE_RETVAL(CoCreateGuid(&guid));
// coverity[fixed_size_dest]
strcpy(&pipe[9], GuidToString(&guid));
strcpy(&pipe[9], GuidToString(&guid, TRUE));
static_sprintf(icon_path, "%s%s.ico", temp_dir, APPLICATION_NAME);
ExtractAppIcon(icon_path, TRUE);
@ -973,7 +802,7 @@ static DWORD WINAPI DownloadISOThread(LPVOID param)
assert((fido_script != NULL) && (fido_len != 0));
static_sprintf(script_path, "%s%s.ps1", temp_dir, GuidToString(&guid));
static_sprintf(script_path, "%s%s.ps1", temp_dir, GuidToString(&guid, TRUE));
hFile = CreateFileU(script_path, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_READONLY, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
uprintf("Unable to create download script '%s': %s", script_path, WindowsErrorString());
@ -1019,6 +848,7 @@ static DWORD WINAPI DownloadISOThread(LPVOID param)
uprintf("Script signature is valid ✓");
#endif
FormatStatus = 0;
dwExitCode = RunCommand(cmdline, app_data_dir, TRUE);
uprintf("Exited download script with code: %d", dwExitCode);
if ((dwExitCode == 0) && PeekNamedPipe(hPipe, NULL, dwPipeSize, NULL, &dwAvail, NULL) && (dwAvail != 0)) {
@ -1040,7 +870,7 @@ static DWORD WINAPI DownloadISOThread(LPVOID param)
#endif
EXT_DECL(img_ext, GetShortName(url), __VA_GROUP__("*.iso"), __VA_GROUP__(lmprintf(MSG_036)));
img_save.Type = VIRTUAL_STORAGE_TYPE_DEVICE_ISO;
img_save.ImagePath = FileDialog(TRUE, NULL, &img_ext, 0);
img_save.ImagePath = FileDialog(TRUE, NULL, &img_ext, NULL);
if (img_save.ImagePath == NULL) {
goto out;
}
@ -1055,7 +885,7 @@ static DWORD WINAPI DownloadISOThread(LPVOID param)
Notification(MSG_INFO, NULL, NULL, lmprintf(MSG_211), lmprintf(MSG_041));
PrintInfo(0, MSG_211);
} else {
Notification(MSG_ERROR, NULL, NULL, lmprintf(MSG_194, GetShortName(url)), lmprintf(MSG_043, WinInetErrorString()));
Notification(MSG_ERROR, NULL, NULL, lmprintf(MSG_194, GetShortName(url)), lmprintf(MSG_043, WindowsErrorString()));
PrintInfo(0, MSG_212);
}
} else {

View File

@ -860,7 +860,7 @@ BOOL ParseSKUSiPolicy(void)
goto out;
}
if (!CompareGUID(&Header->PolicyTypeGUID, &SKU_CODE_INTEGRITY_POLICY)) {
uprintf("ParseSKUSiPolicy: Unexpected Policy Type GUID %s", GuidToString(&Header->PolicyTypeGUID));
uprintf("ParseSKUSiPolicy: Unexpected Policy Type GUID %s", GuidToString(&Header->PolicyTypeGUID, TRUE));
goto out;
}

View File

@ -2,9 +2,9 @@
* Rufus: The Reliable USB Formatting Utility
* Process search functionality
*
* Modified from Process Hacker:
* https://github.com/processhacker2/processhacker2/
* Copyright © 2017-2023 Pete Batard <pete@akeo.ie>
* Modified from System Informer (a.k.a. Process Hacker):
* https://github.com/winsiderss/systeminformer
* Copyright © 2017-2024 Pete Batard <pete@akeo.ie>
* Copyright © 2017 dmex
* Copyright © 2009-2016 wj32
*
@ -31,6 +31,7 @@
#include <assert.h>
#include "rufus.h"
#include "drive.h"
#include "process.h"
#include "missing.h"
#include "msapi_utf8.h"
@ -53,10 +54,10 @@ PF_TYPE_DECL(NTAPI, NTSTATUS, NtAdjustPrivilegesToken, (HANDLE, BOOLEAN, PTOKEN_
PF_TYPE_DECL(NTAPI, NTSTATUS, NtClose, (HANDLE));
static PVOID PhHeapHandle = NULL;
static wchar_t* _wHandleName;
static BOOL _bPartialMatch, _bIgnoreSelf, _bQuiet;
static BYTE access_mask;
extern StrArray BlockingProcess;
static HANDLE hSearchProcessThread = NULL;
static BlockingProcess blocking_process = { 0 };
extern StrArray BlockingProcessList;
/*
* Convert an NT Status to an error message
@ -110,7 +111,6 @@ char* NtStatusError(NTSTATUS Status) {
}
}
static NTSTATUS PhCreateHeap(VOID)
{
NTSTATUS status = STATUS_SUCCESS;
@ -155,7 +155,6 @@ static NTSTATUS PhDestroyHeap(VOID)
* \param Size The number of bytes to allocate.
*
* \return A pointer to the allocated block of memory.
*
*/
static PVOID PhAllocate(SIZE_T Size)
{
@ -173,7 +172,6 @@ static PVOID PhAllocate(SIZE_T Size)
* Frees a block of memory allocated with PhAllocate().
*
* \param Memory A pointer to a block of memory.
*
*/
static VOID PhFree(PVOID Memory)
{
@ -423,10 +421,18 @@ out:
return wcmdline;
}
/**
* The search process thread.
* Note: Avoid using uprintf statements here, as it may lock the thread.
*
* \param param The thread parameters.
*
* \return A thread exit code.
*/
static DWORD WINAPI SearchProcessThread(LPVOID param)
{
const char *access_rights_str[8] = { "n", "r", "w", "rw", "x", "rx", "wx", "rwx" };
char tmp[MAX_PATH];
BOOL bInitSuccess = FALSE;
NTSTATUS status = STATUS_SUCCESS;
PSYSTEM_HANDLE_INFORMATION_EX handles = NULL;
POBJECT_NAME_INFORMATION buffer = NULL;
@ -434,276 +440,536 @@ static DWORD WINAPI SearchProcessThread(LPVOID param)
ULONG_PTR pid[2];
ULONG_PTR last_access_denied_pid = 0;
ULONG bufferSize;
USHORT wHandleNameLen;
wchar_t** wHandleName = NULL;
USHORT* wHandleNameLen = NULL;
HANDLE dupHandle = NULL;
HANDLE processHandle = NULL;
BOOLEAN bFound = FALSE, bGotCmdLine, verbose = !_bQuiet;
HANDLE hLock = NULL;
BOOLEAN bFound = FALSE, bGotCmdLine;
ULONG access_rights = 0;
DWORD size;
char cmdline[MAX_PATH] = { 0 };
wchar_t wexe_path[MAX_PATH], *wcmdline;
int cur_pid;
uint64_t start_time;
char cmdline[MAX_PATH] = { 0 }, tmp[64];
int cur_pid, j, nHandles = 0;
PF_INIT_OR_SET_STATUS(NtQueryObject, Ntdll);
PF_INIT_OR_SET_STATUS(NtDuplicateObject, NtDll);
PF_INIT_OR_SET_STATUS(NtClose, NtDll);
PF_INIT_OR_OUT(NtQueryObject, Ntdll);
PF_INIT_OR_OUT(NtDuplicateObject, NtDll);
PF_INIT_OR_OUT(NtClose, NtDll);
StrArrayClear(&BlockingProcess);
// Initialize the blocking process struct
memset(&blocking_process, 0, sizeof(blocking_process));
hLock = CreateMutexA(NULL, TRUE, NULL);
if (hLock == NULL)
goto out;
blocking_process.hStart = CreateEventA(NULL, TRUE, FALSE, NULL);
if (blocking_process.hStart == NULL)
goto out;
if (!ReleaseMutex(hLock))
goto out;
// Only assign the mutex handle once our init is complete
blocking_process.hLock = hLock;
if (NT_SUCCESS(status))
status = PhCreateHeap();
if (!NT_SUCCESS(PhCreateHeap()))
goto out;
if (NT_SUCCESS(status))
status = PhEnumHandlesEx(&handles);
if (!NT_SUCCESS(status)) {
uprintf("Warning: Could not enumerate process handles: %s", NtStatusError(status));
// Wait until we are signaled active one way or another
if (!blocking_process.bActive &&
(WaitForSingleObject(blocking_process.hStart, INFINITE) != WAIT_OBJECT_0)) {
goto out;
}
pid[0] = (ULONG_PTR)0;
cur_pid = 1;
wHandleNameLen = (USHORT)wcslen(_wHandleName);
bufferSize = 0x200;
buffer = PhAllocate(bufferSize);
if (buffer == NULL)
goto out;
for (i = 0; ; i++) {
ULONG attempts = 8;
PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX handleInfo = NULL;
// We are seeing reports of application crashes due to access
// violation exceptions here, so, since this is not critical code,
// we add an exception handler to ignore them.
TRY_AND_HANDLE(
EXCEPTION_ACCESS_VIOLATION,
{ handleInfo = (i < handles->NumberOfHandles) ? &handles->Handles[i] : NULL; },
{ continue; }
);
if ((dupHandle != NULL) && (processHandle != NtCurrentProcess())) {
pfNtClose(dupHandle);
dupHandle = NULL;
bInitSuccess = TRUE;
while (blocking_process.bActive) {
// Get a lock to our data
if (WaitForSingleObject(hLock, SEARCH_PROCESS_LOCK_TIMEOUT) != WAIT_OBJECT_0)
goto out;
// No handles to check => just sleep for a while
if (blocking_process.nHandles == 0) {
ReleaseMutex(hLock);
Sleep(500);
continue;
}
// Update the current handle's process PID and compare against last
// Note: Be careful about not trying to overflow our list!
TRY_AND_HANDLE(
EXCEPTION_ACCESS_VIOLATION,
{ pid[cur_pid] = (handleInfo != NULL) ? handleInfo->UniqueProcessId : -1; },
{ continue; }
);
if (pid[0] != pid[1]) {
cur_pid = (cur_pid + 1) % 2;
// If we're switching process and found a match, print it
if (bFound) {
static_sprintf (tmp, "● [%06u] %s (%s)", (uint32_t)pid[cur_pid], cmdline, access_rights_str[access_rights & 0x7]);
// tmp may contain a '%' so don't feed it as a naked format string
vuprintf("%s", tmp);
StrArrayAdd(&BlockingProcess, tmp, TRUE);
bFound = FALSE;
access_rights = 0;
// Work on our own copy of the handle names so we don't have to hold the
// mutex for string comparison. Update only if the version has changed.
if (blocking_process.nVersion[0] != blocking_process.nVersion[1]) {
assert(blocking_process.wHandleName != NULL && blocking_process.nHandles != 0);
if (blocking_process.wHandleName == NULL || blocking_process.nHandles == 0) {
ReleaseMutex(hLock);
goto out;
}
// Close the previous handle
if (processHandle != NULL) {
if (processHandle != NtCurrentProcess())
pfNtClose(processHandle);
processHandle = NULL;
if (wHandleName != NULL) {
for (i = 0; i < nHandles; i++)
free(wHandleName[i]);
free(wHandleName);
}
}
CHECK_FOR_USER_CANCEL;
// Exit loop condition
if (i >= handles->NumberOfHandles)
break;
if (handleInfo == NULL)
continue;
// Don't bother with processes we can't access
if (handleInfo->UniqueProcessId == last_access_denied_pid)
continue;
// Filter out handles that aren't opened with Read (bit 0), Write (bit 1) or Execute (bit 5) access
if ((handleInfo->GrantedAccess & 0x23) == 0)
continue;
// Open the process to which the handle we are after belongs, if not already opened
if (pid[0] != pid[1]) {
status = PhOpenProcess(&processHandle, PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
(HANDLE)handleInfo->UniqueProcessId);
// There exists some processes we can't access
if (!NT_SUCCESS(status)) {
uuprintf("SearchProcess: Could not open process %ld: %s",
handleInfo->UniqueProcessId, NtStatusError(status));
processHandle = NULL;
if (status == STATUS_ACCESS_DENIED) {
last_access_denied_pid = handleInfo->UniqueProcessId;
safe_free(wHandleNameLen);
nHandles = blocking_process.nHandles;
wHandleName = calloc(nHandles, sizeof(wchar_t*));
if (wHandleName == NULL) {
ReleaseMutex(hLock);
goto out;
}
wHandleNameLen = calloc(nHandles, sizeof(USHORT));
if (wHandleNameLen == NULL) {
ReleaseMutex(hLock);
goto out;
}
for (i = 0; i < nHandles; i++) {
wHandleName[i] = wcsdup(blocking_process.wHandleName[i]);
wHandleNameLen[i] = (USHORT)wcslen(blocking_process.wHandleName[i]);
if (wHandleName[i] == NULL) {
ReleaseMutex(hLock);
goto out;
}
continue;
}
blocking_process.nVersion[1] = blocking_process.nVersion[0];
blocking_process.nPass = 0;
}
ReleaseMutex(hLock);
start_time = GetTickCount64();
// Get a list of all opened handles
if (!NT_SUCCESS(PhEnumHandlesEx(&handles))) {
Sleep(1000);
continue;
}
// Now duplicate this handle onto our own process, so that we can access its properties
if (processHandle == NtCurrentProcess()) {
if (_bIgnoreSelf)
pid[0] = (ULONG_PTR)0;
cur_pid = 1;
bufferSize = 0x200;
buffer = PhAllocate(bufferSize);
if (buffer == NULL)
goto out;
for (i = 0; blocking_process.bActive; i++) {
ULONG attempts = 8;
PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX handleInfo = NULL;
// We are seeing reports of application crashes due to access
// violation exceptions here, so, since this is not critical code,
// we add an exception handler to ignore them.
TRY_AND_HANDLE(
EXCEPTION_ACCESS_VIOLATION,
{ handleInfo = (i < handles->NumberOfHandles) ? &handles->Handles[i] : NULL; },
{ continue; }
);
if ((dupHandle != NULL) && (processHandle != NtCurrentProcess())) {
pfNtClose(dupHandle);
dupHandle = NULL;
}
// Update the current handle's process PID and compare against last
// Note: Be careful about not trying to overflow our list!
TRY_AND_HANDLE(
EXCEPTION_ACCESS_VIOLATION,
{ pid[cur_pid] = (handleInfo != NULL) ? handleInfo->UniqueProcessId : -1; },
{ continue; }
);
if (pid[0] != pid[1]) {
cur_pid = (cur_pid + 1) % 2;
// If we're switching process and found a match, store it
if (bFound) {
if (WaitForSingleObject(hLock, SEARCH_PROCESS_LOCK_TIMEOUT) == WAIT_OBJECT_0) {
ProcessEntry* pe = blocking_process.Process;
// Prune entries that have not been detected for a few passes
for (j = 0; j < MAX_BLOCKING_PROCESSES; j++)
if (pe[j].pid != 0 && pe[j].seen_on_pass < blocking_process.nPass - 1)
pe[j].pid = 0;
// Try to reuse an existing entry for the current pid
for (j = 0; (j < MAX_BLOCKING_PROCESSES) && (pe[j].pid != pid[cur_pid]); j++);
if (j == MAX_BLOCKING_PROCESSES)
for (j = 0; (j < MAX_BLOCKING_PROCESSES) && (pe[j].pid != 0); j++);
if (j != MAX_BLOCKING_PROCESSES) {
pe[j].pid = pid[cur_pid];
pe[j].access_rights = access_rights & 0x7;
pe[j].seen_on_pass = blocking_process.nPass;
static_strcpy(pe[j].cmdline, cmdline);
} else if (usb_debug) {
// coverity[dont_call]
OutputDebugStringA("SearchProcessThread: No empty slot!\n");
}
ReleaseMutex(hLock);
}
bFound = FALSE;
access_rights = 0;
}
// Close the previous handle
if (processHandle != NULL) {
if (processHandle != NtCurrentProcess())
pfNtClose(processHandle);
processHandle = NULL;
}
}
// Exit thread condition
if (!blocking_process.bActive)
goto out;
// Exit loop condition
if (i >= handles->NumberOfHandles)
break;
if (handleInfo == NULL)
continue;
// Don't bother with processes we can't access
if (handleInfo->UniqueProcessId == last_access_denied_pid)
continue;
// Filter out handles that aren't opened with Read (bit 0), Write (bit 1) or Execute (bit 5) access
if ((handleInfo->GrantedAccess & 0x23) == 0)
continue;
// Open the process to which the handle we are after belongs, if not already opened
if (pid[0] != pid[1]) {
status = PhOpenProcess(&processHandle, PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
(HANDLE)handleInfo->UniqueProcessId);
// There exists some processes we can't access
if (!NT_SUCCESS(status)) {
processHandle = NULL;
if (status == STATUS_ACCESS_DENIED) {
last_access_denied_pid = handleInfo->UniqueProcessId;
}
continue;
}
}
// Now duplicate this handle onto our own process, so that we can access its properties
if (processHandle == NtCurrentProcess())
continue;
dupHandle = (HANDLE)handleInfo->HandleValue;
} else {
status = pfNtDuplicateObject(processHandle, (HANDLE)handleInfo->HandleValue,
NtCurrentProcess(), &dupHandle, 0, 0, 0);
if (!NT_SUCCESS(status))
continue;
}
// Filter non-storage handles. We're not interested in them and they make NtQueryObject() freeze
if (GetFileType(dupHandle) != FILE_TYPE_DISK)
continue;
// Filter non-storage handles. We're not interested in them and they make NtQueryObject() freeze
if (GetFileType(dupHandle) != FILE_TYPE_DISK)
continue;
// A loop is needed because the I/O subsystem likes to give us the wrong return lengths...
do {
ULONG returnSize;
// TODO: We might potentially still need a timeout on ObjectName queries, as PH does...
status = pfNtQueryObject(dupHandle, ObjectNameInformation, buffer, bufferSize, &returnSize);
if (status == STATUS_BUFFER_OVERFLOW || status == STATUS_INFO_LENGTH_MISMATCH ||
status == STATUS_BUFFER_TOO_SMALL) {
uuprintf("SearchProcess: Realloc from %d to %d", bufferSize, returnSize);
bufferSize = returnSize;
PhFree(buffer);
buffer = PhAllocate(bufferSize);
} else {
break;
// A loop is needed because the I/O subsystem likes to give us the wrong return lengths...
do {
ULONG returnSize;
// TODO: We might potentially still need a timeout on ObjectName queries, as PH does...
status = pfNtQueryObject(dupHandle, ObjectNameInformation, buffer, bufferSize, &returnSize);
if (status == STATUS_BUFFER_OVERFLOW || status == STATUS_INFO_LENGTH_MISMATCH ||
status == STATUS_BUFFER_TOO_SMALL) {
bufferSize = returnSize;
PhFree(buffer);
buffer = PhAllocate(bufferSize);
} else {
break;
}
} while (--attempts);
if (!NT_SUCCESS(status))
continue;
for (j = 0; j < nHandles; j++) {
// Don't bother comparing if length of our handle string is larger than the current data
if (wHandleNameLen[j] > buffer->Name.Length)
continue;
// Match against our target string(s)
if (wcsncmp(wHandleName[j], buffer->Name.Buffer, wHandleNameLen[j]) == 0)
break;
}
if (j == nHandles)
continue;
bFound = TRUE;
// Keep a mask of all the access rights being used
access_rights |= handleInfo->GrantedAccess;
// The Executable bit is in a place we don't like => reposition it
if (access_rights & 0x20)
access_rights = (access_rights & 0x03) | 0x04;
access_rights &= 0x07;
// Where possible, try to get the full command line
bGotCmdLine = FALSE;
size = MAX_PATH;
wcmdline = GetProcessCommandLine(processHandle);
if (wcmdline != NULL) {
bGotCmdLine = TRUE;
wchar_to_utf8_no_alloc(wcmdline, cmdline, sizeof(cmdline));
free(wcmdline);
}
// If we couldn't get the full commandline, try to get the executable path
if (!bGotCmdLine)
bGotCmdLine = (GetModuleFileNameExU(processHandle, 0, cmdline, MAX_PATH - 1) != 0);
// The above may not work on all Windows version, so fall back to QueryFullProcessImageName
if (!bGotCmdLine) {
bGotCmdLine = (QueryFullProcessImageNameW(processHandle, 0, wexe_path, &size) != FALSE);
if (bGotCmdLine)
wchar_to_utf8_no_alloc(wexe_path, cmdline, sizeof(cmdline));
}
// Still nothing? Try GetProcessImageFileName. Note that GetProcessImageFileName uses
// '\Device\Harddisk#\Partition#\' instead drive letters
if (!bGotCmdLine) {
bGotCmdLine = (GetProcessImageFileNameW(processHandle, wexe_path, MAX_PATH) != 0);
if (bGotCmdLine)
wchar_to_utf8_no_alloc(wexe_path, cmdline, sizeof(cmdline));
}
// Complete failure => Just craft a default process name that includes the PID
if (!bGotCmdLine) {
static_sprintf(cmdline, "Unknown_Process_%" PRIu64,
(ULONGLONG)handleInfo->UniqueProcessId);
}
} while (--attempts);
if (!NT_SUCCESS(status)) {
uuprintf("SearchProcess: NtQueryObject failed for handle %X of process %ld: %s",
handleInfo->HandleValue, handleInfo->UniqueProcessId, NtStatusError(status));
continue;
}
// Don't bother comparing if we are looking for full match and the length is different
if ((!_bPartialMatch) && (wHandleNameLen != buffer->Name.Length))
continue;
// Likewise, if we are looking for a partial match and the current length is smaller
if ((_bPartialMatch) && (wHandleNameLen > buffer->Name.Length))
continue;
// Match against our target string
if (wcsncmp(_wHandleName, buffer->Name.Buffer, wHandleNameLen) != 0)
continue;
// If we are here, we have a process accessing our target!
bFound = TRUE;
// Keep a mask of all the access rights being used
access_rights |= handleInfo->GrantedAccess;
// The Executable bit is in a place we don't like => reposition it
if (access_rights & 0x20)
access_rights = (access_rights & 0x03) | 0x04;
access_mask |= (BYTE) (access_rights & 0x7) + 0x80; // Bit 7 is always set if a process was found
// If this is the very first process we find, print a header
if (cmdline[0] == 0)
vuprintf("WARNING: The following process(es) or service(s) are accessing %S:", _wHandleName);
// Where possible, try to get the full command line
bGotCmdLine = FALSE;
size = MAX_PATH;
wcmdline = GetProcessCommandLine(processHandle);
if (wcmdline != NULL) {
bGotCmdLine = TRUE;
wchar_to_utf8_no_alloc(wcmdline, cmdline, sizeof(cmdline));
free(wcmdline);
}
// If we couldn't get the full commandline, try to get the executable path
if (!bGotCmdLine)
bGotCmdLine = (GetModuleFileNameExU(processHandle, 0, cmdline, MAX_PATH - 1) != 0);
// The above may not work on all Windows version, so fall back to QueryFullProcessImageName
if (!bGotCmdLine) {
bGotCmdLine = (QueryFullProcessImageNameW(processHandle, 0, wexe_path, &size) != FALSE);
if (bGotCmdLine)
wchar_to_utf8_no_alloc(wexe_path, cmdline, sizeof(cmdline));
}
// Still nothing? Try GetProcessImageFileName. Note that GetProcessImageFileName uses
// '\Device\Harddisk#\Partition#\' instead drive letters
if (!bGotCmdLine) {
bGotCmdLine = (GetProcessImageFileNameW(processHandle, wexe_path, MAX_PATH) != 0);
if (bGotCmdLine)
wchar_to_utf8_no_alloc(wexe_path, cmdline, sizeof(cmdline));
}
// Complete failure => Just craft a default process name that includes the PID
if (!bGotCmdLine) {
static_sprintf(cmdline, "Unknown_Process_%" PRIu64,
(ULONGLONG)handleInfo->UniqueProcessId);
PhFree(buffer);
PhFree(handles);
// We are the only ones updating the counter so no need for lock
blocking_process.nPass++;
// In extended debug mode, notify how much time our search took to the debug facility
if (usb_debug) {
static_sprintf(tmp, "Process search run #%d completed in %llu ms\n",
blocking_process.nPass, GetTickCount64() - start_time);
// coverity[dont_call]
OutputDebugStringA(tmp);
}
Sleep(1000);
}
out:
if (cmdline[0] != 0)
vuprintf("You should close these applications before attempting to reformat the drive.");
else
vuprintf("NOTE: Could not identify the process(es) or service(s) accessing %S", _wHandleName);
if (!bInitSuccess)
uprintf("Warning: Could not start process handle enumerator!");
if (wHandleName != NULL) {
for (i = 0; i < nHandles; i++)
free(wHandleName[i]);
free(wHandleName);
}
safe_free(wHandleNameLen);
PhFree(buffer);
PhFree(handles);
PhDestroyHeap();
if ((hLock != NULL) && (hLock != INVALID_HANDLE_VALUE) &&
(WaitForSingleObject(hLock, 1000) == WAIT_OBJECT_0)) {
blocking_process.hLock = NULL;
blocking_process.bActive = FALSE;
for (i = 0; i < blocking_process.nHandles; i++)
free(blocking_process.wHandleName[i]);
safe_free(blocking_process.wHandleName);
safe_closehandle(blocking_process.hStart);
ReleaseMutex(hLock);
}
safe_closehandle(hLock);
ExitThread(0);
}
/**
* Search all the processes and list the ones that have a specific handle open.
* Start the process search thread.
*
* \param HandleName The name of the handle to look for.
* \param dwTimeOut The maximum amounf of time (ms) that may be spent searching
* \param bPartialMatch Whether partial matches should be allowed.
* \param bIgnoreSelf Whether the current process should be listed.
* \param bQuiet Prints minimal output.
* \return TRUE on success, FALSE otherwise.
*
* \return a byte containing the cumulated access rights (f----xwr) from all the handles found
* with bit 7 ('f') also set if at least one process was found.
*/
BYTE SearchProcess(char* HandleName, DWORD dwTimeOut, BOOL bPartialMatch, BOOL bIgnoreSelf, BOOL bQuiet)
BOOL StartProcessSearch(void)
{
HANDLE handle;
DWORD res = 0;
int i;
_wHandleName = utf8_to_wchar(HandleName);
_bPartialMatch = bPartialMatch;
_bIgnoreSelf = bIgnoreSelf;
_bQuiet = bQuiet;
access_mask = 0x00;
if (hSearchProcessThread != NULL)
return TRUE;
assert(_wHandleName != NULL);
handle = CreateThread(NULL, 0, SearchProcessThread, NULL, 0, NULL);
if (handle == NULL) {
uprintf("Warning: Unable to create conflicting process search thread");
goto out;
hSearchProcessThread = CreateThread(NULL, 0, SearchProcessThread, NULL, 0, NULL);
if (hSearchProcessThread == NULL) {
uprintf("Failed to start process search thread: %s", WindowsErrorString());
return FALSE;
}
res = WaitForSingleObjectWithMessages(handle, dwTimeOut);
if (res == WAIT_TIMEOUT) {
// Timeout - kill the thread
TerminateThread(handle, 0);
uprintf("Search for conflicting processes was interrupted due to timeout");
} else if (res != WAIT_OBJECT_0) {
TerminateThread(handle, 0);
uprintf("Warning: Failed to wait for conflicting process search thread %s", WindowsErrorString());
SetThreadPriority(SearchProcessThread, THREAD_PRIORITY_LOWEST);
// Wait until we have hLock
for (i = 0; (i < 50) && (blocking_process.hLock == NULL); i++)
Sleep(100);
if (i >= 50) {
uprintf("Failed to start process search thread: hLock init failure!");
TerminateThread(hSearchProcessThread, 0);
CloseHandle(hSearchProcessThread);
hSearchProcessThread = NULL;
return FALSE;
}
return TRUE;
}
/**
* Stop the process search thread..
*
*/
void StopProcessSearch(void)
{
if (hSearchProcessThread == NULL)
return;
// No need for a lock on this one
blocking_process.bActive = FALSE;
if (WaitForSingleObject(hSearchProcessThread, SEARCH_PROCESS_LOCK_TIMEOUT) != WAIT_OBJECT_0) {
uprintf("Process search thread did not exit within timeout - forcefully terminating it!");
TerminateThread(hSearchProcessThread, 0);
CloseHandle(hSearchProcessThread);
}
hSearchProcessThread = NULL;
}
/**
* Set up the handles that the process search will run against.
*
* \param DeviceNum The device number for the currently selected drive.
*
* \return TRUE on success, FALSE otherwise.
*
*/
BOOL SetProcessSearch(DWORD DeviceNum)
{
char* PhysicalPath = NULL, DevPath[MAX_PATH];
char drive_letter[27], drive_name[] = "?:";
uint32_t i, nHandles = 0;
wchar_t** wHandleName = NULL;
if (hSearchProcessThread == NULL) {
uprintf("Process search thread is not started!");
return FALSE;
}
assert(blocking_process.hLock != NULL);
// Populate the handle names
wHandleName = calloc(MAX_NUM_HANDLES, sizeof(wchar_t*));
if (wHandleName == NULL)
return FALSE;
// Physical drive handle name
PhysicalPath = GetPhysicalName(DeviceNum);
if (QueryDosDeviceA(&PhysicalPath[4], DevPath, sizeof(DevPath)) != 0)
wHandleName[nHandles++] = utf8_to_wchar(DevPath);
free(PhysicalPath);
// Logical drive(s) handle name(s)
GetDriveLetters(DeviceNum, drive_letter);
for (i = 0; nHandles < MAX_NUM_HANDLES && drive_letter[i]; i++) {
drive_name[0] = drive_letter[i];
if (QueryDosDeviceA(drive_name, DevPath, sizeof(DevPath)) != 0)
wHandleName[nHandles++] = utf8_to_wchar(DevPath);
}
if (WaitForSingleObject(blocking_process.hLock, SEARCH_PROCESS_LOCK_TIMEOUT) != WAIT_OBJECT_0) {
uprintf("Could not obtain process search lock");
free(wHandleName);
nHandles = 0;
return FALSE;
}
if (blocking_process.wHandleName != NULL)
for (i = 0; i < blocking_process.nHandles; i++)
free(blocking_process.wHandleName[i]);
free(blocking_process.wHandleName);
blocking_process.wHandleName = wHandleName;
blocking_process.nHandles = nHandles;
blocking_process.nVersion[0]++;
blocking_process.bActive = TRUE;
if (!SetEvent(blocking_process.hStart))
uprintf("Could not signal start event to process search: %s", WindowsErrorString());
return ReleaseMutex(blocking_process.hLock);
}
/**
* Check whether the corresponding PID is that of a running process.
*
* \param pid The PID of the process to check.
*
* \return TRUE if the process is detected as currently running, FALSE otherwise.
*
*/
static BOOL IsProcessRunning(uint64_t pid)
{
HANDLE hProcess = NULL;
DWORD dwExitCode;
BOOL ret = FALSE;
NTSTATUS status;
PF_INIT_OR_OUT(NtClose, NtDll);
status = PhOpenProcess(&hProcess, PROCESS_QUERY_LIMITED_INFORMATION, (HANDLE)pid);
if (!NT_SUCCESS(status) || (hProcess == NULL))
return FALSE;
if (GetExitCodeProcess(hProcess, &dwExitCode))
ret = (dwExitCode == STILL_ACTIVE);
pfNtClose(hProcess);
out:
free(_wHandleName);
return access_mask;
return ret;
}
/**
* Report the result of the process search.
*
* \param timeout Maximum time that should be spend in this function before aborting (in ms).
* \param access_mask Desired access mask (x = 0x4, w = 0x2, r = 0x1).
* \param bIgnoreStaleProcesses Whether to ignore processes that are no longer active.
*
* \return The combined access mask of all the matching processes found.
* The BlockingProcessList string array is also updated with the results.
*
*/
BYTE GetProcessSearch(uint32_t timeout, uint8_t access_mask, BOOL bIgnoreStaleProcesses)
{
const char* access_rights_str[8] = { "n", "r", "w", "rw", "x", "rx", "wx", "rwx" };
char tmp[MAX_PATH];
int i, j;
uint32_t elapsed = 0;
BYTE returned_mask = 0;
StrArrayClear(&BlockingProcessList);
if (hSearchProcessThread == NULL) {
uprintf("Process search thread is not started!");
return 0;
}
assert(blocking_process.hLock != NULL);
if (blocking_process.hLock == NULL)
return 0;
retry:
if (WaitForSingleObject(blocking_process.hLock, SEARCH_PROCESS_LOCK_TIMEOUT) != WAIT_OBJECT_0)
return 0;
// Make sure we have at least one pass with the current handles in order to report them.
// If we have a timeout, wait until timeout has elapsed to give up.
if ((blocking_process.nVersion[0] != blocking_process.nVersion[1]) ||
(blocking_process.nPass < 1)) {
ReleaseMutex(blocking_process.hLock);
if (elapsed < timeout) {
Sleep(100);
elapsed += 100;
goto retry;
}
if (timeout != 0)
uprintf("Timeout while retrieving conflicting process list");
return 0;
}
for (i = 0, j = 0; i < MAX_BLOCKING_PROCESSES; i++) {
if (blocking_process.Process[i].pid == 0)
continue;
if ((blocking_process.Process[i].access_rights & access_mask) == 0)
continue;
if (bIgnoreStaleProcesses && !IsProcessRunning(blocking_process.Process[i].pid))
continue;
returned_mask |= blocking_process.Process[i].access_rights;
static_sprintf(tmp, "● [%llu] %s (%s)", blocking_process.Process[i].pid, blocking_process.Process[i].cmdline,
access_rights_str[blocking_process.Process[i].access_rights & 0x7]);
StrArrayAdd(&BlockingProcessList, tmp, TRUE);
if (j++ == 0)
uprintf("WARNING: The following application(s) or service(s) are accessing the drive:");
// tmp may contain a '%' so don't feed it as a naked format string
uprintf("%s", tmp);
}
if (j != 0)
uprintf("You should close these applications before retrying the operation.");
ReleaseMutex(blocking_process.hLock);
return returned_mask & access_mask;
}
/**
@ -712,6 +978,10 @@ out:
* be convenient for our usage (since we might be looking for processes preventing
* us to open said target in exclusive mode).
*
* At least on Windows 11, this no longer seems to work as querying a logical or
* physical volume seems to return almost ALL the processes that are running,
* including the ones that are not actually accessing the handle.
*
* \param HandleName The name of the handle to look for.
*
* \return TRUE if processes were found, FALSE otherwise.
@ -729,7 +999,7 @@ BOOL SearchProcessAlt(char* HandleName)
goto out;
// Note that the access rights being used with CreateFile() might matter...
searchHandle = CreateFileA(HandleName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
searchHandle = CreateFileA(HandleName, FILE_READ_ATTRIBUTES | SYNCHRONIZE, FILE_SHARE_READ,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
status = PhQueryProcessesUsingVolumeOrFile(searchHandle, &info);

View File

@ -2,9 +2,9 @@
* Rufus: The Reliable USB Formatting Utility
* Process search functionality
*
* Modified from Process Hacker:
* https://github.com/processhacker2/processhacker2/
* Copyright © 2017-2019 Pete Batard <pete@akeo.ie>
* Modified from System Informer (a.k.a. Process Hacker):
* https://github.com/winsiderss/systeminformer
* Copyright © 2017-2023 Pete Batard <pete@akeo.ie>
* Copyright © 2017 dmex
* Copyright © 2009-2016 wj32
*
@ -25,6 +25,7 @@
#include <windows.h>
#include <winnt.h>
#include <winternl.h>
#include <stdint.h>
#pragma once
@ -44,6 +45,7 @@
#define STATUS_OBJECT_NAME_NOT_FOUND ((NTSTATUS)0xC0000034L)
#define STATUS_OBJECT_PATH_INVALID ((NTSTATUS)0xC0000039L)
#define STATUS_SHARING_VIOLATION ((NTSTATUS)0xC0000043L)
#define STATUS_PROCEDURE_NOT_FOUND ((NTSTATUS)0xC000007AL)
#define STATUS_INSUFFICIENT_RESOURCES ((NTSTATUS)0xC000009AL)
#define STATUS_NOT_SUPPORTED ((NTSTATUS)0xC00000BBL)
@ -294,3 +296,25 @@ typedef struct _RTL_HEAP_PARAMETERS
#define SE_TIME_ZONE_PRIVILEGE (34L)
#define SE_CREATE_SYMBOLIC_LINK_PRIVILEGE (35L)
#define SE_MAX_WELL_KNOWN_PRIVILEGE SE_CREATE_SYMBOLIC_LINK_PRIVILEGE
#define MAX_NUM_HANDLES 16
#define MAX_BLOCKING_PROCESSES 16
#define SEARCH_PROCESS_LOCK_TIMEOUT 2000
typedef struct {
uint64_t pid; // PID of the process
uint8_t access_rights; // rwx access rights
uint32_t seen_on_pass; // nPass value of when this process was last detected
char cmdline[MAX_PATH]; // Command line for the process
} ProcessEntry;
typedef struct {
BOOL bActive; // Indicates whether the search for processes is currently active
uint32_t nVersion[2]; // Version indicator for the handle name list.
uint32_t nHandles; // Number of handle names in the list below
wchar_t** wHandleName; // Handle names we search against
HANDLE hLock; // Global lock to request for modifying this structure
HANDLE hStart; // Event indicating that the search for processes can be started
ProcessEntry Process[MAX_BLOCKING_PROCESSES]; // Fixed size process list
uint32_t nPass; // Incremental counter of how many passes we ran
} BlockingProcess;

View File

@ -1,6 +1,6 @@
/*
* Rufus: The Reliable USB Formatting Utility
* Copyright © 2011-2023 Pete Batard <pete@akeo.ie>
* Copyright © 2011-2024 Pete Batard <pete@akeo.ie>
*
* 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
@ -93,7 +93,7 @@ static unsigned int timer;
static char uppercase_select[2][64], uppercase_start[64], uppercase_close[64], uppercase_cancel[64];
extern HANDLE update_check_thread, wim_thread;
extern BOOL enable_iso, enable_joliet, enable_rockridge, enable_extra_hashes;
extern BOOL enable_iso, enable_joliet, enable_rockridge, enable_extra_hashes, is_bootloader_revoked;
extern BYTE* fido_script;
extern HWND hFidoDlg;
extern uint8_t* grub2_buf;
@ -128,19 +128,20 @@ BOOL advanced_mode_device, advanced_mode_format, allow_dual_uefi_bios, detect_fa
BOOL usb_debug, use_fake_units, preserve_timestamps = FALSE, fast_zeroing = FALSE, app_changed_size = FALSE;
BOOL zero_drive = FALSE, list_non_usb_removable_drives = FALSE, enable_file_indexing, large_drive = FALSE;
BOOL write_as_image = FALSE, write_as_esp = FALSE, use_vds = FALSE, ignore_boot_marker = FALSE;
BOOL appstore_version = FALSE, is_vds_available = TRUE, persistent_log = FALSE;
BOOL appstore_version = FALSE, is_vds_available = TRUE, persistent_log = FALSE, has_ffu_support = FALSE;
BOOL expert_mode = FALSE;
float fScale = 1.0f;
int dialog_showing = 0, selection_default = BT_IMAGE, persistence_unit_selection = -1, imop_win_sel = 0;
int default_fs, fs_type, boot_type, partition_type, target_type;
int force_update = 0, default_thread_priority = THREAD_PRIORITY_ABOVE_NORMAL;
char szFolderPath[MAX_PATH], app_dir[MAX_PATH], system_dir[MAX_PATH], temp_dir[MAX_PATH], sysnative_dir[MAX_PATH];
char app_data_dir[MAX_PATH], user_dir[MAX_PATH];
char app_data_dir[MAX_PATH], user_dir[MAX_PATH], cur_dir[MAX_PATH];
char embedded_sl_version_str[2][12] = { "?.??", "?.??" };
char embedded_sl_version_ext[2][32];
char ClusterSizeLabel[MAX_CLUSTER_SIZES][64];
char msgbox[1024], msgbox_title[32], *ini_file = NULL, *image_path = NULL, *short_image_path;
char *archive_path = NULL, image_option_txt[128], *fido_url = NULL;
StrArray BlockingProcess, ImageList;
char *archive_path = NULL, image_option_txt[128], *fido_url = NULL, *save_image_type = NULL;
StrArray BlockingProcessList, ImageList;
// Number of steps for each FS for FCC_STRUCTURE_PROGRESS
const int nb_steps[FS_MAX] = { 5, 5, 12, 1, 10, 1, 1, 1, 1 };
const char* flash_type[BADLOCKS_PATTERN_TYPES] = { "SLC", "MLC", "TLC" };
@ -183,8 +184,8 @@ static void SetAllowedFileSystems(void)
break;
case BT_IMAGE:
allowed_filesystem[FS_NTFS] = TRUE;
// Don't allow anything besides NTFS if the image has a >4GB file
if ((image_path != NULL) && (img_report.has_4GB_file))
// Don't allow anything besides NTFS if the image has a >4GB file or explicitly requires NTFS
if ((image_path != NULL) && (img_report.has_4GB_file || img_report.needs_ntfs))
break;
if (!HAS_WINDOWS(img_report) || (target_type != TT_BIOS) || allow_dual_uefi_bios) {
if (!HAS_WINTOGO(img_report) || (ComboBox_GetCurItemData(hImageOption) != IMOP_WIN_TO_GO)) {
@ -1013,7 +1014,7 @@ BOOL CALLBACK LogCallback(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
log_size = GetDlgItemTextU(hDlg, IDC_LOG_EDIT, log_buffer, log_size);
if (log_size != 0) {
log_size--; // remove NUL terminator
filepath = FileDialog(TRUE, user_dir, &log_ext, 0);
filepath = FileDialog(TRUE, user_dir, &log_ext, NULL);
if (filepath != NULL)
FileIO(FILE_IO_WRITE, filepath, &log_buffer, &log_size);
safe_free(filepath);
@ -1133,13 +1134,18 @@ static void DisplayISOProps(void)
(img_report.wininst_version >> 16) & 0xff, (img_report.wininst_version >> 8) & 0xff,
(img_report.wininst_version >= SPECIAL_WIM_VERSION) ? "+": "");
}
PRINT_ISO_PROP(img_report.has_symlinks,
" Note: This ISO uses symbolic links, which will not be replicated due to file system");
PRINT_ISO_PROP((img_report.has_symlinks == SYMLINKS_RR),
" limitations. Because of this, some features from this image may not work...");
PRINT_ISO_PROP((img_report.has_symlinks == SYMLINKS_UDF),
" limitations. Because of this, the size required for the target media may be much\r\n"
" larger than size of the ISO...");
if (img_report.needs_ntfs) {
uprintf(" Note: This ISO uses symbolic links and was not designed to work without them.\r\n"
" Because of this, only NTFS will be allowed as the target file system.");
} else {
PRINT_ISO_PROP(img_report.has_symlinks,
" Note: This ISO uses symbolic links, which may not be replicated due to file system");
PRINT_ISO_PROP((img_report.has_symlinks == SYMLINKS_RR),
" limitations. Because of this, some features from this image may not work...");
PRINT_ISO_PROP((img_report.has_symlinks == SYMLINKS_UDF),
" limitations. Because of this, the size required for the target media may be much\r\n"
" larger than size of the ISO...");
}
}
// Insert the image name into the Boot selection dropdown and (re)populate the Image option dropdown
@ -1255,7 +1261,8 @@ DWORD WINAPI ImageScanThread(LPVOID param)
const char* redhat8_derivative[] = {
"^AlmaLinux-[8-9].*", // AlmaLinux 8.x and 9.x
"^Fedora.*-3[3-9].*", // Fedora 33-39
"^CentOS.*-[8-9].*", // CentOS and CentOS Stream 8.and 9.x
"^CentOS.*-[8-9].*", // CentOS and CentOS Stream 8.x and 9.x
"^Circle.*-[8-9].*", // Circle Linux 8.x.and 9.x
"^OL-[8-9].*", // Oracle Linux 8.x and 9.x
"^RHEL-[8-9].*", // Red Hat 8.x and 9.x
"^Rocky-[8-9].*", // Rocky Linux 8.x and 9.x
@ -1337,7 +1344,8 @@ DWORD WINAPI ImageScanThread(LPVOID param)
uprintf(" Image is a FORCED non-bootable image");
else
uprintf(" Image is a %sbootable %s image",
(img_report.compression_type != BLED_COMPRESSION_NONE) ? "compressed " : "", img_report.is_vhd ? "VHD" : "disk");
(img_report.compression_type != BLED_COMPRESSION_NONE && img_report.compression_type < BLED_COMPRESSION_MAX) ?
"compressed " : "", img_report.is_vhd ? "VHD" : "disk");
selection_default = BT_IMAGE;
}
@ -1429,9 +1437,10 @@ static DWORD WINAPI BootCheckThread(LPVOID param)
const char* ldlinux = "ldlinux";
const char* syslinux = "syslinux";
const char* ldlinux_ext[3] = { "sys", "bss", "c32" };
char tmp[MAX_PATH], tmp2[MAX_PATH], efi[MAX_PATH], c;
char tmp[MAX_PATH], tmp2[MAX_PATH], c;
syslinux_ldlinux_len[0] = 0; syslinux_ldlinux_len[1] = 0;
is_bootloader_revoked = FALSE;
safe_free(grub2_buf);
if (ComboBox_GetCurSel(hDeviceList) == CB_ERR)
@ -1449,7 +1458,7 @@ static DWORD WINAPI BootCheckThread(LPVOID param)
goto out;
if ((size_check) && (img_report.projected_size > (uint64_t)SelectedDrive.DiskSize)) {
// This ISO image is too big for the selected target
MessageBoxExU(hMainDialog, lmprintf(MSG_089), lmprintf(MSG_088), MB_OK|MB_ICONERROR|MB_IS_RTL, selected_langid);
MessageBoxExU(hMainDialog, lmprintf(MSG_089), lmprintf(MSG_088), MB_OK | MB_ICONERROR | MB_IS_RTL, selected_langid);
goto out;
}
if (IS_DD_BOOTABLE(img_report)) {
@ -1489,14 +1498,14 @@ static DWORD WINAPI BootCheckThread(LPVOID param)
if (is_windows_to_go) {
if (fs_type != FS_NTFS) {
// Windows To Go only works for NTFS
MessageBoxExU(hMainDialog, lmprintf(MSG_097, "Windows To Go"), lmprintf(MSG_092), MB_OK|MB_ICONERROR|MB_IS_RTL, selected_langid);
MessageBoxExU(hMainDialog, lmprintf(MSG_097, "Windows To Go"), lmprintf(MSG_092), MB_OK | MB_ICONERROR | MB_IS_RTL, selected_langid);
goto out;
}
if (SelectedDrive.MediaType != FixedMedia) {
if ((target_type == TT_UEFI) && (partition_type == PARTITION_STYLE_GPT) && (WindowsVersion.BuildNumber < 15000)) {
// Up to Windows 10 Creators Update (1703), we were screwed, since we need access to 2 partitions at the same time.
// Thankfully, the newer Windows allow mounting multiple partitions on the same REMOVABLE drive.
MessageBoxExU(hMainDialog, lmprintf(MSG_198), lmprintf(MSG_190), MB_OK|MB_ICONERROR|MB_IS_RTL, selected_langid);
MessageBoxExU(hMainDialog, lmprintf(MSG_198), lmprintf(MSG_190), MB_OK | MB_ICONERROR | MB_IS_RTL, selected_langid);
goto out;
}
}
@ -1513,8 +1522,8 @@ static DWORD WINAPI BootCheckThread(LPVOID param)
if ((WindowsVersion.Version >= WINDOWS_8) && IS_WINDOWS_1X(img_report)) {
StrArray options;
int arch = _log2(img_report.has_efi >> 1);
uint8_t map[8] = { 0 }, b = 1;
StrArrayCreate(&options, 2);
uint16_t map[16] = { 0 }, b = 1;
StrArrayCreate(&options, 8);
StrArrayAdd(&options, lmprintf(MSG_332), TRUE);
MAP_BIT(UNATTEND_OFFLINE_INTERNAL_DRIVES);
if (img_report.win_version.build >= 22500) {
@ -1528,16 +1537,20 @@ static DWORD WINAPI BootCheckThread(LPVOID param)
MAP_BIT(UNATTEND_DUPLICATE_LOCALE);
StrArrayAdd(&options, lmprintf(MSG_331), TRUE);
MAP_BIT(UNATTEND_NO_DATA_COLLECTION);
if (expert_mode) {
StrArrayAdd(&options, lmprintf(MSG_346), TRUE);
MAP_BIT(UNATTEND_FORCE_S_MODE);
}
i = CustomSelectionDialog(BS_AUTOCHECKBOX, lmprintf(MSG_327), lmprintf(MSG_328),
options.String, options.Index, remap8(unattend_xml_mask, map, FALSE), username_index);
options.String, options.Index, remap16(unattend_xml_mask, map, FALSE), username_index);
StrArrayDestroy(&options);
if (i < 0)
goto out;
// Remap i to the correct bit positions before calling CreateUnattendXml()
i = remap8(i, map, TRUE);
i = remap16(i, map, TRUE);
unattend_xml_path = CreateUnattendXml(arch, i | UNATTEND_WINDOWS_TO_GO);
// Keep the bits we didn't process
unattend_xml_mask &= ~(remap8(0xff, map, TRUE));
unattend_xml_mask &= ~(remap16(0x1ff, map, TRUE));
// And add back the bits we did process
unattend_xml_mask |= i;
WriteSetting32(SETTING_WUE_OPTIONS, (UNATTEND_DEFAULT_MASK << 16) | unattend_xml_mask);
@ -1575,8 +1588,8 @@ static DWORD WINAPI BootCheckThread(LPVOID param)
if ((WindowsVersion.Version >= WINDOWS_8) && IS_WINDOWS_1X(img_report) && (!is_windows_to_go)) {
StrArray options;
int arch = _log2(img_report.has_efi >> 1);
uint8_t map[8] = { 0 }, b = 1;
StrArrayCreate(&options, 4);
uint16_t map[16] = { 0 }, b = 1;
StrArrayCreate(&options, 10);
if (IS_WINDOWS_11(img_report)) {
StrArrayAdd(&options, lmprintf(MSG_329), TRUE);
MAP_BIT(UNATTEND_SECUREBOOT_TPM_MINRAM);
@ -1594,15 +1607,19 @@ static DWORD WINAPI BootCheckThread(LPVOID param)
MAP_BIT(UNATTEND_NO_DATA_COLLECTION);
StrArrayAdd(&options, lmprintf(MSG_335), TRUE);
MAP_BIT(UNATTEND_DISABLE_BITLOCKER);
if (expert_mode) {
StrArrayAdd(&options, lmprintf(MSG_346), TRUE);
MAP_BIT(UNATTEND_FORCE_S_MODE);
}
i = CustomSelectionDialog(BS_AUTOCHECKBOX, lmprintf(MSG_327), lmprintf(MSG_328),
options.String, options.Index, remap8(unattend_xml_mask, map, FALSE), username_index);
options.String, options.Index, remap16(unattend_xml_mask, map, FALSE), username_index);
StrArrayDestroy(&options);
if (i < 0)
goto out;
i = remap8(i, map, TRUE);
i = remap16(i, map, TRUE);
unattend_xml_path = CreateUnattendXml(arch, i);
// Remember the user preferences for the current session.
unattend_xml_mask &= ~(remap8(0xff, map, TRUE));
unattend_xml_mask &= ~(remap16(0x1ff, map, TRUE));
unattend_xml_mask |= i;
WriteSetting32(SETTING_WUE_OPTIONS, (UNATTEND_DEFAULT_MASK << 16) | unattend_xml_mask);
}
@ -1620,25 +1637,23 @@ static DWORD WINAPI BootCheckThread(LPVOID param)
}
// Check UEFI bootloaders for revocation
if (target_type == TT_UEFI) {
if (IS_EFI_BOOTABLE(img_report)) {
// coverity[swapped_arguments]
if (GetTempFileNameU(temp_dir, APPLICATION_NAME, 0, tmp) != 0) {
for (i = 0; i < ARRAYSIZE(efi_bootname) + 1; i++) {
if ((img_report.has_efi & (1 << i)) == 0)
continue;
if (i == 0)
static_strcpy(efi, bootmgr_efi_name);
else
static_sprintf(efi, "%s/%s", efi_dirname, efi_bootname[i - 1]);
if (ExtractISOFile(image_path, efi, tmp, FILE_ATTRIBUTE_NORMAL) == 0) {
uprintf("Warning: Failed to extract '%s' to check for UEFI revocation", efi);
// ExtractISOFile() is case sensitive, so we must use
for (i = 0; i < ARRAYSIZE(img_report.efi_boot_path) && img_report.efi_boot_path[i][0] != 0; i++) {
if (ExtractISOFile(image_path, img_report.efi_boot_path[i], tmp, FILE_ATTRIBUTE_NORMAL) == 0) {
uprintf("Warning: Failed to extract '%s' to check for UEFI revocation", img_report.efi_boot_path[i]);
continue;
}
r = IsBootloaderRevoked(tmp);
if (r > 0) {
MessageBoxExU(hMainDialog, lmprintf(MSG_339,
is_bootloader_revoked = TRUE;
r = MessageBoxExU(hMainDialog, lmprintf(MSG_339,
(r == 1) ? lmprintf(MSG_340) : lmprintf(MSG_341, "Error code: 0xc0000428")),
lmprintf(MSG_338), MB_ICONWARNING | MB_IS_RTL, selected_langid);
lmprintf(MSG_338), MB_OKCANCEL | MB_ICONWARNING | MB_IS_RTL, selected_langid);
if (r == IDCANCEL)
goto out;
break;
}
}
@ -1677,7 +1692,7 @@ static DWORD WINAPI BootCheckThread(LPVOID param)
fclose(fd);
} else {
r = MessageBoxExU(hMainDialog, lmprintf(MSG_116, img_report.grub2_version, GRUB2_PACKAGE_VERSION),
lmprintf(MSG_115), MB_YESNOCANCEL|MB_ICONWARNING|MB_IS_RTL, selected_langid);
lmprintf(MSG_115), MB_YESNOCANCEL | MB_ICONWARNING | MB_IS_RTL, selected_langid);
if (r == IDCANCEL)
goto out;
else if (r == IDYES) {
@ -1717,7 +1732,7 @@ static DWORD WINAPI BootCheckThread(LPVOID param)
if ((partition_type == PARTITION_STYLE_MBR) && HAS_SYSLINUX(img_report)) {
if (SL_MAJOR(img_report.sl_version) < 5) {
IGNORE_RETVAL(_chdirU(app_data_dir));
for (i=0; i<NB_OLD_C32; i++) {
for (i = 0; i<NB_OLD_C32; i++) {
if (img_report.has_old_c32[i]) {
if (!in_files_dir) {
IGNORE_RETVAL(_mkdir(FILES_DIR));
@ -1735,7 +1750,7 @@ static DWORD WINAPI BootCheckThread(LPVOID param)
} else {
PrintInfo(0, MSG_204, old_c32_name[i]);
if (MessageBoxExU(hMainDialog, lmprintf(MSG_084, old_c32_name[i], old_c32_name[i]),
lmprintf(MSG_083, old_c32_name[i]), MB_YESNO|MB_ICONWARNING|MB_IS_RTL, selected_langid) == IDYES) {
lmprintf(MSG_083, old_c32_name[i]), MB_YESNO | MB_ICONWARNING | MB_IS_RTL, selected_langid) == IDYES) {
static_sprintf(tmp, "%s-%s", syslinux, embedded_sl_version_str[0]);
IGNORE_RETVAL(_mkdir(tmp));
static_sprintf(tmp, "%s/%s-%s/%s", FILES_URL, syslinux, embedded_sl_version_str[0], old_c32_name[i]);
@ -1775,7 +1790,7 @@ static DWORD WINAPI BootCheckThread(LPVOID param)
} else {
r = MessageBoxExU(hMainDialog, lmprintf(MSG_114, img_report.sl_version_str, img_report.sl_version_ext,
embedded_sl_version_str[1], embedded_sl_version_ext[1]),
lmprintf(MSG_115), MB_YESNO|MB_ICONWARNING|MB_IS_RTL, selected_langid);
lmprintf(MSG_115), MB_YESNO | MB_ICONWARNING | MB_IS_RTL, selected_langid);
if (r != IDYES)
goto out;
for (i=0; i<2; i++) {
@ -1834,7 +1849,7 @@ static DWORD WINAPI BootCheckThread(LPVOID param)
PrintInfo(0, MSG_206, tmp);
// MSG_104: "Syslinux v5.0 or later requires a '%s' file to be installed"
r = MessageBoxExU(hMainDialog, lmprintf(MSG_104, "Syslinux v5.0", tmp, "Syslinux v5+", tmp),
lmprintf(MSG_103, tmp), MB_YESNOCANCEL|MB_ICONWARNING|MB_IS_RTL, selected_langid);
lmprintf(MSG_103, tmp), MB_YESNOCANCEL | MB_ICONWARNING | MB_IS_RTL, selected_langid);
if (r == IDCANCEL)
goto out;
if (r == IDYES) {
@ -1864,7 +1879,7 @@ static DWORD WINAPI BootCheckThread(LPVOID param)
IGNORE_RETVAL(_chdirU(app_data_dir));
IGNORE_RETVAL(_mkdir(FILES_DIR));
IGNORE_RETVAL(_chdir(FILES_DIR));
if (DownloadToFileOrBufferEx(DISKCOPY_URL, tmp, DISKCOPY_USER_AGENT, NULL, hMainDialog, FALSE) != DISKCOPY_SIZE) {
if (DownloadToFileOrBufferEx(DISKCOPY_URL, tmp, SYMBOL_SERVER_USER_AGENT, NULL, hMainDialog, FALSE) != DISKCOPY_SIZE) {
ret = BOOTCHECK_DOWNLOAD_ERROR;
goto out;
}
@ -1883,7 +1898,7 @@ static DWORD WINAPI BootCheckThread(LPVOID param)
static_sprintf(tmp, "grldr");
PrintInfo(0, MSG_206, tmp);
r = MessageBoxExU(hMainDialog, lmprintf(MSG_104, "Grub4DOS 0.4", tmp, "Grub4DOS", tmp),
lmprintf(MSG_103, tmp), MB_YESNOCANCEL|MB_ICONWARNING|MB_IS_RTL, selected_langid);
lmprintf(MSG_103, tmp), MB_YESNOCANCEL | MB_ICONWARNING | MB_IS_RTL, selected_langid);
if (r == IDCANCEL)
goto out;
if (r == IDYES) {
@ -2096,7 +2111,7 @@ static void InitDialog(HWND hDlg)
IGNORE_RETVAL(ComboBox_SetCurSel(hDiskID, 0));
// Create the string arrays
StrArrayCreate(&BlockingProcess, 16);
StrArrayCreate(&BlockingProcessList, 16);
StrArrayCreate(&ImageList, 16);
// Set various checkboxes
CheckDlgButton(hDlg, IDC_QUICK_FORMAT, BST_CHECKED);
@ -2160,85 +2175,6 @@ static void PrintStatusTimeout(const char* str, BOOL val)
PrintStatus(STATUS_MSG_TIMEOUT, (val)?MSG_250:MSG_251, str);
}
// Check for conflicting processes accessing the drive.
// If bPrompt is true, ask the user whether they want to proceed.
// dwTimeOut is the maximum amount of time we allow for this call to execute (in ms)
// If bPrompt is false, the return value is the amount of time remaining before
// dwTimeOut would expire (or zero if we spent more than dwTimeout in this procedure).
// If bPrompt is true, the return value is 0 on error, dwTimeOut on success.
DWORD CheckDriveAccess(DWORD dwTimeOut, BOOL bPrompt)
{
uint32_t i, j;
DWORD ret = 0, proceed = TRUE;
BYTE access_mask;
char *PhysicalPath = NULL, DevPath[MAX_PATH];
char drive_letter[27], drive_name[] = "?:";
char title[128];
uint64_t start_time = GetTickCount64(), cur_time, end_time = start_time + dwTimeOut;
// Get the current selected device
DWORD DeviceNum = (DWORD)ComboBox_GetCurItemData(hDeviceList);
if ((DeviceNum < 0x80) || (DeviceNum == (DWORD)-1))
return FALSE;
// "Checking for conflicting processes..."
if (bPrompt)
PrintInfo(0, MSG_278);
// Search for any blocking processes against the physical drive
PhysicalPath = GetPhysicalName(DeviceNum);
if (QueryDosDeviceA(&PhysicalPath[4], DevPath, sizeof(DevPath)) != 0) {
access_mask = SearchProcess(DevPath, dwTimeOut, TRUE, TRUE, TRUE);
CHECK_FOR_USER_CANCEL;
if (access_mask != 0) {
proceed = FALSE;
uprintf("Found potentially blocking process(es) against %s:", &PhysicalPath[4]);
for (j = 0; j < BlockingProcess.Index; j++)
// BlockingProcess.String[j] may contain a '%' so don't feed it as a naked format string
uprintf("%s", BlockingProcess.String[j]);
}
}
// Search for any blocking processes against the logical volume(s)
GetDriveLetters(DeviceNum, drive_letter);
for (i = 0; drive_letter[i]; i++) {
drive_name[0] = drive_letter[i];
if (QueryDosDeviceA(drive_name, DevPath, sizeof(DevPath)) != 0) {
StrArrayClear(&BlockingProcess);
cur_time = GetTickCount64();
if (cur_time >= end_time)
break;
access_mask = SearchProcess(DevPath, (DWORD)(end_time - cur_time), TRUE, TRUE, TRUE);
CHECK_FOR_USER_CANCEL;
// Ignore if all we have is read-only
if ((access_mask & 0x06) || (access_mask == 0x80)) {
proceed = FALSE;
uprintf("Found potentially blocking process(es) against %s", drive_name);
for (j = 0; j < BlockingProcess.Index; j++)
// BlockingProcess.String[j] may contain a '%' so don't feed it as a naked format string
uprintf("%s", BlockingProcess.String[j]);
}
}
}
// Prompt the user if we detected blocking processes
if (bPrompt && !proceed) {
ComboBox_GetTextU(hDeviceList, title, sizeof(title));
proceed = Notification(MSG_WARNING_QUESTION, NULL, NULL, title, lmprintf(MSG_132));
}
if (bPrompt) {
ret = proceed ? dwTimeOut : 0;
} else {
ret = (DWORD)(GetTickCount64() - start_time);
ret = (dwTimeOut > ret) ? (dwTimeOut - ret) : 0;
}
out:
PrintInfo(0, MSG_210);
free(PhysicalPath);
return ret;
}
/*
* Main dialog callback
*/
@ -2349,7 +2285,8 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
SHChangeNotifyDeregister(ulRegister);
PostQuitMessage(0);
ClearDrives();
StrArrayDestroy(&BlockingProcess);
StopProcessSearch();
StrArrayDestroy(&BlockingProcessList);
StrArrayDestroy(&ImageList);
DestroyAllTooltips();
DestroyWindow(hLogDialog);
@ -2438,12 +2375,19 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
if (HIWORD(wParam) != CBN_SELCHANGE)
break;
nb_devices = ComboBox_GetCount(hDeviceList);
PrintStatusDebug(0, (nb_devices==1)?MSG_208:MSG_209, nb_devices);
PrintStatusDebug(0, (nb_devices == 1) ? MSG_208 : MSG_209, nb_devices);
PopulateProperties();
nDeviceIndex = ComboBox_GetCurSel(hDeviceList);
DeviceNum = (nDeviceIndex == CB_ERR) ? 0 : (DWORD)ComboBox_GetItemData(hDeviceList, nDeviceIndex);
SendMessage(hMainDialog, WM_COMMAND, (CBN_SELCHANGE_INTERNAL << 16) | IDC_FILE_SYSTEM,
ComboBox_GetCurSel(hFileSystem));
if (nb_devices == 0) {
// No need to run the process search if no device is selected
StopProcessSearch();
} else if (!StartProcessSearch() || !SetProcessSearch(DeviceNum)) {
uprintf("Failed to start conflicting process search");
StopProcessSearch();
}
break;
case IDC_IMAGE_OPTION:
if (HIWORD(wParam) != CBN_SELCHANGE)
@ -2570,7 +2514,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
EXT_DECL(arch_ext, NULL, __VA_GROUP__("*.zip"), __VA_GROUP__(lmprintf(MSG_309)));
if (image_path == NULL)
break;
archive_path = FileDialog(FALSE, NULL, &arch_ext, 0);
archive_path = FileDialog(FALSE, NULL, &arch_ext, NULL);
if (archive_path != NULL) {
struct __stat64 stat64 = { 0 };
_stat64U(archive_path, &stat64);
@ -2591,10 +2535,13 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
img_provided = FALSE; // One off thing...
} else {
char* old_image_path = image_path;
// If declared globaly, lmprintf(MSG_036) would be called on each message...
EXT_DECL(img_ext, NULL, __VA_GROUP__("*.iso;*.img;*.vhd;*.usb;*.bz2;*.bzip2;*.gz;*.lzma;*.xz;*.Z;*.zip;*.wim;*.esd;*.vtsi"),
__VA_GROUP__(lmprintf(MSG_036)));
image_path = FileDialog(FALSE, NULL, &img_ext, 0);
char extensions[128] = "*.iso;*.img;*.vhd;*.vhdx;*.usb;*.bz2;*.bzip2;*.gz;*.lzma;*.xz;*.Z;*.zip;*.wic;*.wim;*.esd;*.vtsi";
if (has_ffu_support)
strcat(extensions, ";*.ffu");
// If declared globaly, lmprintf(MSG_280) would be called on each message...
EXT_DECL(img_ext, NULL, __VA_GROUP__(extensions),
__VA_GROUP__(lmprintf(MSG_280)));
image_path = FileDialog(FALSE, NULL, &img_ext, NULL);
if (image_path == NULL) {
if (old_image_path != NULL) {
// Reselect previous image
@ -2642,7 +2589,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
EnableControls(FALSE, FALSE);
FormatStatus = 0;
LastWriteError = 0;
StrArrayClear(&BlockingProcess);
StrArrayClear(&BlockingProcessList);
no_confirmation_on_cancel = FALSE;
SendMessage(hMainDialog, UM_PROGRESS_INIT, 0, 0);
selection_default = (int)ComboBox_GetCurItemData(hBootType);
@ -2687,7 +2634,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
}
break;
case IDC_SAVE:
SaveVHD();
VhdSaveImage();
break;
case IDM_SELECT:
case IDM_DOWNLOAD:
@ -3037,8 +2984,15 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
}
}
if (!CheckDriveAccess(SEARCH_PROCESS_TIMEOUT, TRUE))
goto aborted_start;
// Detect processes that have write (0x2) or exec (0x4) permissions against our drive.
// Ideally, exec should be no big deal, but Windows complains on USB ejection if a
// process such as cmd.exe holds exec rights, so we follow suit.
if (GetProcessSearch(SEARCH_PROCESS_TIMEOUT, 0x06, TRUE)) {
char title[128];
ComboBox_GetTextU(hDeviceList, title, sizeof(title));
if (!Notification(MSG_WARNING_QUESTION, NULL, NULL, title, lmprintf(MSG_132)))
goto aborted_start;
}
GetWindowTextU(hDeviceList, tmp, ARRAYSIZE(tmp));
if (MessageBoxExU(hMainDialog, lmprintf(MSG_003, tmp),
@ -3120,8 +3074,9 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
PrintInfo(0, MSG_212);
MessageBeep(MB_ICONERROR);
FlashTaskbar(dialog_handle);
if (BlockingProcess.Index > 0) {
ListDialog(lmprintf(MSG_042), lmprintf(MSG_055), BlockingProcess.String, BlockingProcess.Index);
GetProcessSearch(0, 0x07, FALSE);
if (BlockingProcessList.Index > 0) {
ListDialog(lmprintf(MSG_042), lmprintf(MSG_055), BlockingProcessList.String, BlockingProcessList.Index);
} else {
if (WindowsVersion.Version >= WINDOWS_10) {
// Try to detect if 'Controlled Folder Access' is enabled on Windows 10 or later. See also:
@ -3314,45 +3269,63 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
// Retrieve various app & system directories.
if (GetCurrentDirectoryU(sizeof(app_dir), app_dir) == 0) {
uprintf("Could not get current directory: %s", WindowsErrorString());
app_dir[0] = 0;
uprintf("Could not get application directory: %s", WindowsErrorString());
static_strcpy(app_dir, ".\\");
} else {
// Microsoft has a bad habit of making some of its APIs (_chdir/_wchdir) break
// when app_dir is a drive letter that doesn't have a trailing backslash. For
// instance _chdir("F:") does not change the directory, whereas _chdir("F:\\")
// does. So make sure we always have a trailing backslash.
static_strcat(app_dir, "\\");
}
// Microsoft has a bad habit of making some of its APIs (_chdir/_wchdir) break
// when app_dir is a drive letter that doesn't have a trailing backslash. For
// instance _chdir("F:") does not change the directory, whereas _chdir("F:\\")
// does. So make sure we add a trailing backslash if the app_dir is a drive.
if ((app_dir[1] == ':') && (app_dir[2] == 0)) {
app_dir[2] = '\\';
app_dir[3] = 0;
}
if (GetSystemDirectoryU(system_dir, sizeof(system_dir)) == 0) {
uprintf("Could not get system directory: %s", WindowsErrorString());
static_strcpy(system_dir, "C:\\Windows\\System32");
// In the wonderful world of Microsoft Windows, GetCurrentDirectory() returns the
// directory where the application resides, instead of the real current directory
// so we need another method to resolve the *ACTUAL* current directory.
static_strcpy(cur_dir, ".\\");
hFile = CreateFileU(cur_dir, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS, NULL);
if ((hFile == INVALID_HANDLE_VALUE) ||
(GetFinalPathNameByHandleU(hFile, cur_dir, sizeof(cur_dir), FILE_NAME_OPENED) == 0) ||
((strstr(cur_dir, "\\\\?\\") != cur_dir) && (strstr(cur_dir, "\\\\.\\") != cur_dir))) {
uprintf("Could not get current directory from '%s': %s", cur_dir, WindowsErrorString());
static_strcpy(cur_dir, ".\\");
} else {
// Need to remove the '\\?\' prefix and reappend the trailing '\'
strcpy(cur_dir, &cur_dir[4]);
static_strcat(cur_dir, "\\");
}
safe_closehandle(hFile);
// Per documentation, the returned string ends with a backslash
if (GetTempPathU(sizeof(temp_dir), temp_dir) == 0) {
uprintf("Could not get temp directory: %s", WindowsErrorString());
static_strcpy(temp_dir, ".\\");
static_strcpy(temp_dir, cur_dir);
} else {
// Some folks have found nothing better than configure their Windows installation to use
// a symlink for their temp dir, and it so happens that the Windows WIM mounting facility,
// which we need for applying the WUE options, can't handle symlinked directories. So we
// *attempt* to resolve the actual symlinked temp dir for this super limited number of
// users, with the hope that doing so is not going to break stuff elsewhere...
HANDLE handle = CreateFileU(temp_dir, GENERIC_READ, FILE_SHARE_READ, NULL,
hFile = CreateFileU(temp_dir, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
// GetFinalPathNameByHandle returns a UNC path, which should be prefixed by '\\?\' or '\\.\'
if ((GetFinalPathNameByHandleU(handle, temp_dir, sizeof(temp_dir), FILE_NAME_OPENED) == 0) ||
if ((hFile == INVALID_HANDLE_VALUE) ||
(GetFinalPathNameByHandleU(hFile, temp_dir, sizeof(temp_dir), FILE_NAME_OPENED) == 0) ||
((strstr(temp_dir, "\\\\?\\") != temp_dir) && (strstr(temp_dir, "\\\\.\\") != temp_dir))) {
uprintf("Could not get actual temp directory: %s", WindowsErrorString());
static_strcpy(temp_dir, ".\\");
uprintf("Could not get actual temp directory from '%s': %s", temp_dir, WindowsErrorString());
static_strcpy(temp_dir, cur_dir);
} else {
// Need to remove the '\\?\' prefix or else we'll get issues with the Fido icon
strcpy(temp_dir, &temp_dir[4]);
// And me must re-append the '\' that gets removed by GetFinalPathNameByHandle()
static_strcat(temp_dir, "\\");
}
CloseHandle(handle);
safe_closehandle(hFile);
}
if (GetSystemDirectoryU(system_dir, sizeof(system_dir)) == 0) {
uprintf("Could not get system directory: %s", WindowsErrorString());
static_strcpy(system_dir, "C:\\Windows\\System32");
}
if (!SHGetSpecialFolderPathU(NULL, app_data_dir, CSIDL_LOCAL_APPDATA, FALSE)) {
uprintf("Could not get app data directory: %s", WindowsErrorString());
@ -3380,14 +3353,20 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
}
}
#endif
uprintf("Cur dir: '%s'", cur_dir);
uprintf("App dir: '%s'", app_dir);
uprintf("Sys dir: '%s'", sysnative_dir);
uprintf("Usr dir: '%s'", user_dir);
uprintf("Dat dir: '%s'", app_data_dir);
uprintf("Tmp dir: '%s'", temp_dir);
// Look for a rufus.app file in the current app directory
// Since Microsoft makes it downright impossible to pass an arg in the app manifest
// and the automated VS2019 package building process doesn't like renaming the .exe
// right under its nose (else we would use the same trick as for portable vs regular)
// we use yet another workaround to detect if we are running the AppStore version...
static_sprintf(ini_path, "%s\\rufus.app", app_dir);
if (PathFileExistsU(ini_path)) {
static_sprintf(tmp_path, "%srufus.app", app_dir);
if (PathFileExistsU(tmp_path)) {
appstore_version = TRUE;
goto skip_args_processing;
}
@ -3518,7 +3497,7 @@ skip_args_processing:
uprintf("AppStore version detected");
// Look for a .ini file in the current app directory
static_sprintf(ini_path, "%s\\rufus.ini", app_dir);
static_sprintf(ini_path, "%srufus.ini", app_dir);
fd = fopenU(ini_path, ini_flags); // Will create the file if portable mode is requested
// Using the string directly in safe_strcmp() would call GetSignatureName() twice
tmp = GetSignatureName(NULL, NULL, FALSE);
@ -3529,7 +3508,7 @@ skip_args_processing:
static_strcpy(app_data_dir, app_dir);
fclose(fd);
}
uprintf("Will use settings from %s", (ini_file != NULL)?"INI file":"registry");
uprintf("Will use settings from %s", (ini_file != NULL) ? "INI file" : "registry");
// Use the locale specified by the settings, if any
tmp = ReadSettingStr(SETTING_LOCALE);
@ -3554,8 +3533,10 @@ skip_args_processing:
enable_file_indexing = ReadSettingBool(SETTING_ENABLE_FILE_INDEXING);
enable_VHDs = !ReadSettingBool(SETTING_DISABLE_VHDS);
enable_extra_hashes = ReadSettingBool(SETTING_ENABLE_EXTRA_HASHES);
expert_mode = ReadSettingBool(SETTING_EXPERT_MODE);
ignore_boot_marker = ReadSettingBool(SETTING_IGNORE_BOOT_MARKER);
persistent_log = ReadSettingBool(SETTING_PERSISTENT_LOG);
save_image_type = ReadSettingStr(SETTING_PREFERRED_SAVE_IMAGE_TYPE);
// This restores the Windows User Experience/unattend.xml mask from the saved user
// settings, and is designed to work even if we add new options later.
wue_options = ReadSetting32(SETTING_WUE_OPTIONS);
@ -3576,7 +3557,7 @@ skip_args_processing:
init_localization();
// Seek for a loc file in the application directory
static_sprintf(loc_file, "%s\\%s", app_dir, rufus_loc);
static_sprintf(loc_file, "%s%s", app_dir, rufus_loc);
if (GetFileAttributesU(loc_file) == INVALID_FILE_ATTRIBUTES) {
uprintf("loc file not found in current directory - embedded one will be used");
@ -3649,7 +3630,7 @@ skip_args_processing:
// Prevent 2 applications from running at the same time, unless "/W" is passed as an option
// in which case we wait for the mutex to be relinquished
if ((safe_strlen(lpCmdLine)==2) && (lpCmdLine[0] == '/') && (lpCmdLine[1] == 'W'))
if ((safe_strlen(lpCmdLine) == 2) && (lpCmdLine[0] == '/') && (lpCmdLine[1] == 'W'))
wait_for_mutex = 150; // Try to acquire the mutex for 15 seconds
mutex = CreateMutexA(NULL, TRUE, "Global/" APPLICATION_NAME);
for (;(wait_for_mutex>0) && (mutex != NULL) && (GetLastError() == ERROR_ALREADY_EXISTS); wait_for_mutex--) {
@ -3673,9 +3654,8 @@ skip_args_processing:
IGNORE_RETVAL(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE));
// Some dialogs have Rich Edit controls and won't display without this
if (GetLibraryHandle("Riched20") == NULL) {
uprintf("Could not load RichEdit library - some dialogs may not display: %s\n", WindowsErrorString());
}
if (GetLibraryHandle("Riched20") == NULL)
uprintf("Could not load RichEdit library - some dialogs may not display: %s", WindowsErrorString());
// Increase the application privileges (SE_DEBUG_PRIVILEGE), so that we can report
// the Windows Services preventing access to the disk or volume we want to format.
@ -3698,6 +3678,9 @@ skip_args_processing:
// Detect CPU acceleration for SHA-1/SHA-256
cpu_has_sha1_accel = DetectSHA1Acceleration();
cpu_has_sha256_accel = DetectSHA256Acceleration();
// FFU support started with Windows 10 1709 (through FfuProvider.dll)
static_sprintf(tmp_path, "%s\\dism\\FfuProvider.dll", sysnative_dir);
has_ffu_support = (_accessU(tmp_path, 0) == 0);
relaunch:
ubprintf("Localization set to '%s'", selected_locale->txt[0]);
@ -3956,7 +3939,7 @@ extern int TestHashes(void);
}
// Alt-O => Save from Optical drive to ISO
if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'O')) {
SaveISO();
IsoSaveImage();
continue;
}
// Alt-P => Toggle GPT ESP to and from Basic Data type (Windows 10 or later)
@ -4057,6 +4040,14 @@ extern int TestHashes(void);
}
// Other hazardous cheat modes require Ctrl + Alt
// Ctrl-Alt-E => Expert Mode
if ((msg.message == WM_KEYDOWN) && (msg.wParam == 'E') &&
(GetKeyState(VK_CONTROL) & 0x8000) && (GetKeyState(VK_MENU) & 0x8000)) {
expert_mode = !expert_mode;
WriteSettingBool(SETTING_EXPERT_MODE, expert_mode);
PrintStatusTimeout(lmprintf(MSG_347), expert_mode);
continue;
}
// Ctrl-Alt-F => List non USB removable drives such as eSATA, etc - CAUTION!!!
if ((msg.message == WM_KEYDOWN) && (msg.wParam == 'F') &&
(GetKeyState(VK_CONTROL) & 0x8000) && (GetKeyState(VK_MENU) & 0x8000)) {
@ -4110,16 +4101,22 @@ extern int TestHashes(void);
}
out:
_chdirU(app_dir);
// Destroy the hogger mutex first, so that the cmdline app can exit and we can delete it
if (attached_console && !disable_hogger) {
if (hogmutex != NULL) {
ReleaseMutex(hogmutex);
safe_closehandle(hogmutex);
// Unconditional delete with retry, just in case...
for (i = 0; (!DeleteFileA(cmdline_hogger)) && (i <= 10); i++)
Sleep(200);
}
// Kill the update check thread if running
if (update_check_thread != NULL)
TerminateThread(update_check_thread, 1);
if ((!external_loc_file) && (loc_file[0] != 0))
DeleteFileU(loc_file);
if ((!external_loc_file) && (loc_file[0] != 0)) {
if (!DeleteFileU(loc_file))
uprintf("Could not delete '%s': %s", loc_file, WindowsErrorString());
}
DestroyAllTooltips();
ClrAlertPromptHook();
exit_localization();
@ -4133,7 +4130,8 @@ out:
safe_free(fido_script);
safe_free(pe256ssp);
if (argv != NULL) {
for (i=0; i<argc; i++) safe_free(argv[i]);
for (i = 0; i < argc; i++)
safe_free(argv[i]);
safe_free(argv);
}
if (lgp_set)
@ -4141,17 +4139,13 @@ out:
if ((!automount) && (!SetAutoMount(FALSE)))
uprintf("Failed to restore AutoMount to disabled");
ubflush();
_chdirU(app_dir);
// Unconditional delete with retry, just in case...
for (i = 0; (!DeleteFileA(cmdline_hogger)) && (i <= 10); i++)
Sleep(200);
CloseHandle(mutex);
CoUninitialize();
CLOSE_OPENED_LIBRARIES;
if (attached_console) {
SetWindowPos(GetConsoleWindow(), HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
FreeConsole();
}
CoUninitialize();
CLOSE_OPENED_LIBRARIES;
safe_closehandle(mutex);
uprintf("*** " APPLICATION_NAME " exit ***\n");
#ifdef _CRTDBG_MAP_ALLOC
_CrtDumpMemoryLeaks();

View File

@ -1,6 +1,6 @@
/*
* Rufus: The Reliable USB Formatting Utility
* Copyright © 2011-2023 Pete Batard <pete@akeo.ie>
* Copyright © 2011-2024 Pete Batard <pete@akeo.ie>
*
* 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
@ -87,8 +87,8 @@
#define STATUS_MSG_TIMEOUT 3500 // How long should cheat mode messages appear for on the status bar
#define WRITE_RETRIES 4
#define WRITE_TIMEOUT 5000 // How long we should wait between write retries (in ms)
#define SEARCH_PROCESS_TIMEOUT 10000 // How long we should search for conflicting processes before giving up (in ms)
#define NET_SESSION_TIMEOUT 3500 // How long we should wait to connect, send or receive internet data
#define SEARCH_PROCESS_TIMEOUT 5000 // How long we should wait to get the conflicting process data (in ms)
#define NET_SESSION_TIMEOUT 3500 // How long we should wait to connect, send or receive internet data (in ms)
#define FS_DEFAULT FS_FAT32
#define SINGLE_CLUSTERSIZE_DEFAULT 0x00000100
#define BADLOCKS_PATTERN_TYPES 5
@ -121,10 +121,10 @@
#define SEVENZIP_URL "https://7-zip.org/"
// Generated by following https://randomascii.wordpress.com/2013/03/09/symbols-the-microsoft-way/
#define DISKCOPY_URL "https://msdl.microsoft.com/download/symbols/diskcopy.dll/54505118173000/diskcopy.dll"
#define DISKCOPY_USER_AGENT "Microsoft-Symbol-Server/10.0.22621.755"
#define DISKCOPY_SIZE 0x16ee00
#define DISKCOPY_IMAGE_OFFSET 0x66d8
#define DISKCOPY_IMAGE_SIZE 0x168000
#define SYMBOL_SERVER_USER_AGENT "Microsoft-Symbol-Server/10.0.22621.755"
#define DEFAULT_ESP_MOUNT_POINT "S:\\"
#define IS_POWER_OF_2(x) ((x != 0) && (((x) & ((x) - 1)) == 0))
#define IGNORE_RETVAL(expr) do { (void)(expr); } while(0)
@ -364,12 +364,28 @@ typedef struct {
uint16_t revision;
} winver_t;
/* We can't use the Microsoft enums as we want to have RISC-V */
enum ArchType {
ARCH_UNKNOWN = 0,
ARCH_X86_32,
ARCH_X86_64,
ARCH_ARM_32,
ARCH_ARM_64,
ARCH_IA_64,
ARCH_RISCV_32,
ARCH_RISCV_64,
ARCH_RISCV_128,
ARCH_EBC,
ARCH_MAX
};
typedef struct {
char label[192]; // 3*64 to account for UTF-8
char usb_label[192]; // converted USB label for workaround
char cfg_path[128]; // path to the ISO's isolinux.cfg
char reactos_path[128]; // path to the ISO's freeldr.sys or setupldr.sys
char wininst_path[MAX_WININST][64]; // path to the Windows install image(s)
char efi_boot_path[ARCH_MAX][30]; // paths of detected UEFI bootloaders
char efi_img_path[128]; // path to an efi.img file
uint64_t image_size;
uint64_t archive_size;
@ -396,11 +412,12 @@ typedef struct {
BOOLEAN has_old_c32[NB_OLD_C32];
BOOLEAN has_old_vesamenu;
BOOLEAN has_efi_syslinux;
BOOLEAN needs_syslinux_overwrite;
BOOLEAN has_grub4dos;
uint8_t has_grub2;
BOOLEAN has_compatresources_dll;
BOOLEAN has_kolibrios;
BOOLEAN needs_syslinux_overwrite;
BOOLEAN needs_ntfs;
BOOLEAN uses_casper;
BOOLEAN uses_minint;
uint8_t compression_type;
@ -450,12 +467,20 @@ typedef struct {
* to define an 'ext_t my_extensions' variable initialized with the relevant attributes.
*/
typedef struct ext_t {
const size_t count;
size_t count;
const char* filename;
const char** extension;
const char** description;
} ext_t;
/* DLL address resolver */
typedef struct {
char* path;
uint32_t count;
char** name;
uint32_t* address; // 32-bit will do, as we're not dealing with >4GB DLLs...
} dll_resolver_t;
#ifndef __VA_GROUP__
#define __VA_GROUP__(...) __VA_ARGS__
#endif
@ -476,21 +501,6 @@ typedef enum TASKBAR_PROGRESS_FLAGS
TASKBAR_PAUSED = 0x8
} TASKBAR_PROGRESS_FLAGS;
/* We can't use the Microsoft enums as we want to have RISC-V */
enum ArchType {
ARCH_UNKNOWN = 0,
ARCH_X86_32,
ARCH_X86_64,
ARCH_ARM_32,
ARCH_ARM_64,
ARCH_IA_64,
ARCH_RISCV_32,
ARCH_RISCV_64,
ARCH_RISCV_128,
ARCH_EBC,
ARCH_MAX
};
static __inline USHORT GetApplicationArch(void)
{
#if defined(_M_AMD64)
@ -537,6 +547,13 @@ enum WindowsVersion {
WINDOWS_MAX = 0xFFFF,
};
typedef struct {
DWORD Major;
DWORD Minor;
DWORD Micro;
DWORD Nano;
} version_t;
typedef struct {
DWORD Version;
DWORD Major;
@ -556,6 +573,7 @@ typedef struct {
#define UNATTEND_DUPLICATE_LOCALE 0x00020
#define UNATTEND_SET_USER 0x00040
#define UNATTEND_DISABLE_BITLOCKER 0x00080
#define UNATTEND_FORCE_S_MODE 0x00100
#define UNATTEND_DEFAULT_MASK 0x000FF
#define UNATTEND_WINDOWS_TO_GO 0x10000 // Special flag for Windows To Go
@ -564,7 +582,7 @@ typedef struct {
#define UNATTEND_OOBE_SHELL_SETUP_MASK (UNATTEND_NO_DATA_COLLECTION | UNATTEND_SET_USER)
#define UNATTEND_OOBE_INTERNATIONAL_MASK (UNATTEND_DUPLICATE_LOCALE)
#define UNATTEND_OOBE_MASK (UNATTEND_OOBE_SHELL_SETUP_MASK | UNATTEND_OOBE_INTERNATIONAL_MASK | UNATTEND_DISABLE_BITLOCKER)
#define UNATTEND_OFFLINE_SERVICING_MASK (UNATTEND_OFFLINE_INTERNAL_DRIVES)
#define UNATTEND_OFFLINE_SERVICING_MASK (UNATTEND_OFFLINE_INTERNAL_DRIVES | UNATTEND_FORCE_S_MODE)
#define UNATTEND_DEFAULT_SELECTION_MASK (UNATTEND_SECUREBOOT_TPM_MINRAM | UNATTEND_NO_ONLINE_ACCOUNT | UNATTEND_OFFLINE_INTERNAL_DRIVES)
/*
@ -599,6 +617,7 @@ extern char sysnative_dir[MAX_PATH], app_data_dir[MAX_PATH], *image_path, *fido_
* Shared prototypes
*/
extern void GetWindowsVersion(windows_version_t* WindowsVersion);
extern version_t* GetExecutableVersion(const char* path);
extern const char* WindowsErrorString(void);
extern void DumpBufferHex(void *buf, size_t size);
extern void PrintStatusInfo(BOOL info, BOOL debug, unsigned int duration, int msg_id, ...);
@ -612,7 +631,7 @@ extern void _UpdateProgressWithInfo(int op, int msg, uint64_t processed, uint64_
#define UpdateProgressWithInfoForce(op, msg, processed, total) _UpdateProgressWithInfo(op, msg, processed, total, TRUE)
#define UpdateProgressWithInfoInit(hProgressDialog, bNoAltMode) UpdateProgressWithInfo(OP_INIT, (int)bNoAltMode, (uint64_t)(uintptr_t)hProgressDialog, 0);
extern const char* StrError(DWORD error_code, BOOL use_default_locale);
extern char* GuidToString(const GUID* guid);
extern char* GuidToString(const GUID* guid, BOOL bDecorated);
extern GUID* StringToGuid(const char* str);
extern char* SizeToHumanReadable(uint64_t size, BOOL copy_to_log, BOOL fake_units);
extern char* TimestampToHumanReadable(uint64_t ts);
@ -643,16 +662,15 @@ extern int64_t ExtractISOFile(const char* iso, const char* iso_file, const char*
extern BOOL CopySKUSiPolicy(const char* drive_name);
extern BOOL HasEfiImgBootLoaders(void);
extern BOOL DumpFatDir(const char* path, int32_t cluster);
extern char* MountISO(const char* path);
extern void UnMountISO(void);
extern BOOL InstallSyslinux(DWORD drive_index, char drive_letter, int fs);
extern uint16_t GetSyslinuxVersion(char* buf, size_t buf_size, char** ext);
extern BOOL SetAutorun(const char* path);
extern char* FileDialog(BOOL save, char* path, const ext_t* ext, DWORD options);
extern char* FileDialog(BOOL save, char* path, const ext_t* ext, UINT* selected_ext);
extern BOOL FileIO(enum file_io_type io_type, char* path, char** buffer, DWORD* size);
extern unsigned char* GetResource(HMODULE module, char* name, char* type, const char* desc, DWORD* len, BOOL duplicate);
extern DWORD GetResourceSize(HMODULE module, char* name, char* type, const char* desc);
extern DWORD RunCommand(const char* cmdline, const char* dir, BOOL log);
extern DWORD RunCommandWithProgress(const char* cmdline, const char* dir, BOOL log, int msg);
#define RunCommand(cmd, dir, log) RunCommandWithProgress(cmd, dir, log, 0)
extern BOOL CompareGUID(const GUID *guid1, const GUID *guid2);
extern BOOL MountRegistryHive(const HKEY key, const char* pszHiveName, const char* pszHivePath);
extern BOOL UnmountRegistryHive(const HKEY key, const char* pszHiveName);
@ -712,8 +730,10 @@ extern char* ToLocaleName(DWORD lang_id);
extern void SetAlertPromptMessages(void);
extern BOOL SetAlertPromptHook(void);
extern void ClrAlertPromptHook(void);
extern DWORD CheckDriveAccess(DWORD dwTimeOut, BOOL bPrompt);
extern BYTE SearchProcess(char* HandleName, DWORD dwTimeout, BOOL bPartialMatch, BOOL bIgnoreSelf, BOOL bQuiet);
extern BOOL StartProcessSearch(void);
extern void StopProcessSearch(void);
extern BOOL SetProcessSearch(DWORD DeviceNum);
extern BYTE GetProcessSearch(uint32_t timeout, uint8_t access_mask, BOOL bIgnoreStaleProcesses);
extern BOOL EnablePrivileges(void);
extern void FlashTaskbar(HANDLE handle);
extern DWORD WaitForSingleObjectWithMessages(HANDLE hHandle, DWORD dwMilliseconds);
@ -721,6 +741,7 @@ extern HICON CreateMirroredIcon(HICON hiconOrg);
extern HANDLE CreatePreallocatedFile(const char* lpFileName, DWORD dwDesiredAccess,
DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
DWORD dwFlagsAndAttributes, LONGLONG fileSize);
extern uint32_t ResolveDllAddress(dll_resolver_t* resolver);
#define GetTextWidth(hDlg, id) GetTextSize(GetDlgItem(hDlg, id), NULL).cx
DWORD WINAPI HashThread(void* param);
@ -806,7 +827,7 @@ out:
if (pf##proc == NULL) {uprintf("Unable to locate %s() in '%s.dll': %s", \
#proc, #name, WindowsErrorString()); goto out;} } while(0)
#define PF_INIT_OR_SET_STATUS(proc, name) do {PF_INIT(proc, name); \
if ((pf##proc == NULL) && (NT_SUCCESS(status))) status = STATUS_NOT_IMPLEMENTED; } while(0)
if ((pf##proc == NULL) && (NT_SUCCESS(status))) status = STATUS_PROCEDURE_NOT_FOUND; } while(0)
#if defined(_MSC_VER)
#define TRY_AND_HANDLE(exception, TRY_CODE, EXCEPTION_CODE) __try TRY_CODE \
__except (GetExceptionCode() == exception ? EXCEPTION_EXECUTE_HANDLER : \

View File

@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
IDD_DIALOG DIALOGEX 12, 12, 232, 326
STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU
EXSTYLE WS_EX_ACCEPTFILES
CAPTION "Rufus 4.2.2060"
CAPTION "Rufus 4.5.2113"
FONT 9, "Segoe UI Symbol", 400, 0, 0x0
BEGIN
LTEXT "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP
@ -392,8 +392,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 4,2,2060,0
PRODUCTVERSION 4,2,2060,0
FILEVERSION 4,5,2113,0
PRODUCTVERSION 4,5,2113,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@ -411,13 +411,13 @@ BEGIN
VALUE "Comments", "https://rufus.ie"
VALUE "CompanyName", "Akeo Consulting"
VALUE "FileDescription", "Rufus"
VALUE "FileVersion", "4.2.2060"
VALUE "FileVersion", "4.5.2113"
VALUE "InternalName", "Rufus"
VALUE "LegalCopyright", "© 2011-2023 Pete Batard (GPL v3)"
VALUE "LegalCopyright", "© 2011-2024 Pete Batard (GPL v3)"
VALUE "LegalTrademarks", "https://www.gnu.org/licenses/gpl-3.0.html"
VALUE "OriginalFilename", "rufus-4.2.exe"
VALUE "OriginalFilename", "rufus-4.5.exe"
VALUE "ProductName", "Rufus"
VALUE "ProductVersion", "4.2.2060"
VALUE "ProductVersion", "4.5.2113"
END
END
BLOCK "VarFileInfo"

View File

@ -1,7 +1,7 @@
/*
* Rufus: The Reliable USB Formatting Utility
* Settings access, through either registry or INI file
* Copyright © 2015-2022 Pete Batard <pete@akeo.ie>
* Copyright © 2015-2023 Pete Batard <pete@akeo.ie>
*
* 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
@ -19,6 +19,7 @@
#include <windows.h>
#include <stdint.h>
#include "rufus.h"
#include "msapi_utf8.h"
#include "registry.h"
#pragma once
@ -41,6 +42,7 @@ extern char* ini_file;
#define SETTING_ENABLE_USB_DEBUG "EnableUsbDebug"
#define SETTING_ENABLE_VMDK_DETECTION "EnableVmdkDetection"
#define SETTING_ENABLE_WIN_DUAL_EFI_BIOS "EnableWindowsDualUefiBiosMode"
#define SETTING_EXPERT_MODE "ExpertMode"
#define SETTING_FORCE_LARGE_FAT32_FORMAT "ForceLargeFat32Formatting"
#define SETTING_IGNORE_BOOT_MARKER "IgnoreBootMarker"
#define SETTING_INCLUDE_BETAS "CheckForBetas"
@ -52,6 +54,7 @@ extern char* ini_file;
#define SETTING_USE_UDF_VERSION "UseUdfVersion"
#define SETTING_USE_VDS "UseVds"
#define SETTING_PERSISTENT_LOG "PersistentLog"
#define SETTING_PREFERRED_SAVE_IMAGE_TYPE "PreferredSaveImageType"
#define SETTING_PRESERVE_TIMESTAMPS "PreserveTimestamps"
#define SETTING_VERBOSE_UPDATES "VerboseUpdateCheck"
#define SETTING_WUE_OPTIONS "WindowsUserExperienceOptions"

View File

@ -1,7 +1,7 @@
/*
* Rufus: The Reliable USB Formatting Utility
* Standard Windows function calls
* Copyright © 2013-2023 Pete Batard <pete@akeo.ie>
* Copyright © 2013-2024 Pete Batard <pete@akeo.ie>
*
* 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
@ -26,6 +26,7 @@
#include <gpedit.h>
#include <assert.h>
#include "re.h"
#include "rufus.h"
#include "missing.h"
#include "resource.h"
@ -34,6 +35,15 @@
#include "settings.h"
// MinGW doesn't yet know these (from wldp.h)
typedef enum WLDP_WINDOWS_LOCKDOWN_MODE
{
WLDP_WINDOWS_LOCKDOWN_MODE_UNLOCKED = 0,
WLDP_WINDOWS_LOCKDOWN_MODE_TRIAL,
WLDP_WINDOWS_LOCKDOWN_MODE_LOCKED,
WLDP_WINDOWS_LOCKDOWN_MODE_MAX,
} WLDP_WINDOWS_LOCKDOWN_MODE, * PWLDP_WINDOWS_LOCKDOWN_MODE;
windows_version_t WindowsVersion = { 0 };
/*
@ -70,8 +80,9 @@ BOOL htab_create(uint32_t nel, htab_table* htab)
if (htab == NULL) {
return FALSE;
}
assert(htab->table == NULL);
if (htab->table != NULL) {
uprintf("warning: htab_create() was called with a non empty table");
uprintf("Warning: htab_create() was called with a non empty table");
return FALSE;
}
@ -86,7 +97,7 @@ BOOL htab_create(uint32_t nel, htab_table* htab)
// allocate memory and zero out.
htab->table = (htab_entry*)calloc(htab->size + 1, sizeof(htab_entry));
if (htab->table == NULL) {
uprintf("could not allocate space for hash table\n");
uprintf("Could not allocate space for hash table");
return FALSE;
}
@ -156,7 +167,7 @@ uint32_t htab_hash(char* str, htab_table* htab)
// existing hash
return idx;
}
// uprintf("hash collision ('%s' vs '%s')\n", str, htab->table[idx].str);
// uprintf("Hash collision ('%s' vs '%s')", str, htab->table[idx].str);
// Second hash function, as suggested in [Knuth]
hval2 = 1 + hval % (htab->size - 2);
@ -186,19 +197,20 @@ uint32_t htab_hash(char* str, htab_table* htab)
// Not found => New entry
// If the table is full return an error
assert(htab->filled < htab->size);
if (htab->filled >= htab->size) {
uprintf("hash table is full (%d entries)", htab->size);
uprintf("Hash table is full (%d entries)", htab->size);
return 0;
}
safe_free(htab->table[idx].str);
htab->table[idx].used = hval;
htab->table[idx].str = (char*) malloc(safe_strlen(str)+1);
htab->table[idx].str = (char*) malloc(safe_strlen(str) + 1);
if (htab->table[idx].str == NULL) {
uprintf("could not duplicate string for hash table\n");
uprintf("Could not duplicate string for hash table");
return 0;
}
memcpy(htab->table[idx].str, str, safe_strlen(str)+1);
memcpy(htab->table[idx].str, str, safe_strlen(str) + 1);
++htab->filled;
return idx;
@ -292,10 +304,18 @@ static const char* GetEdition(DWORD ProductType)
case 0x000000A5: return "Pro for Education N";
case 0x000000AB: return "Enterprise G"; // I swear Microsoft are just making up editions...
case 0x000000AC: return "Enterprise G N";
case 0x000000B2: return "Cloud";
case 0x000000B3: return "Cloud N";
case 0x000000B6: return "Home OS";
case 0x000000B7: return "Cloud E";
case 0x000000B8: return "Cloud E N";
case 0x000000B7: case 0x000000CB: return "Cloud E";
case 0x000000B9: return "IoT OS";
case 0x000000BA: case 0x000000CA: return "Cloud E N";
case 0x000000BB: return "IoT Edge OS";
case 0x000000BC: return "IoT Enterprise";
case 0x000000BD: return "Lite";
case 0x000000BF: return "IoT Enterprise S";
case 0x000000C0: case 0x000000C2: case 0x000000C3: case 0x000000C4: case 0x000000C5: case 0x000000C6: return "XBox";
case 0x000000C7: case 0x000000C8: case 0x00000196: case 0x00000197: case 0x00000198: return "Azure Server";
case 0xABCDABCD: return "(Unlicensed)";
default:
static_sprintf(unknown_edition_str, "(Unknown Edition 0x%02X)", (uint32_t)ProductType);
@ -303,6 +323,25 @@ static const char* GetEdition(DWORD ProductType)
}
}
PF_TYPE_DECL(WINAPI, HRESULT, WldpQueryWindowsLockdownMode, (PWLDP_WINDOWS_LOCKDOWN_MODE));
BOOL isSMode(void)
{
BOOL r = FALSE;
WLDP_WINDOWS_LOCKDOWN_MODE mode;
PF_INIT_OR_OUT(WldpQueryWindowsLockdownMode, Wldp);
HRESULT hr = pfWldpQueryWindowsLockdownMode(&mode);
if (hr != S_OK) {
SetLastError((DWORD)hr);
uprintf("Could not detect S Mode: %s", WindowsErrorString());
} else {
r = (mode != WLDP_WINDOWS_LOCKDOWN_MODE_UNLOCKED);
}
out:
return r;
}
/*
* Modified from smartmontools' os_win32.cpp
*/
@ -450,6 +489,50 @@ void GetWindowsVersion(windows_version_t* windows_version)
safe_sprintf(vptr, vlen, " (Build %lu.%lu)", windows_version->BuildNumber, windows_version->Ubr);
else
safe_sprintf(vptr, vlen, " (Build %lu)", windows_version->BuildNumber);
vptr = &windows_version->VersionStr[safe_strlen(windows_version->VersionStr)];
vlen = sizeof(windows_version->VersionStr) - safe_strlen(windows_version->VersionStr) - 1;
if (isSMode())
safe_sprintf(vptr, vlen, " in S Mode");
}
/*
* Why oh why does Microsoft make it so convoluted to retrieve a measly executable's version number ?
*/
version_t* GetExecutableVersion(const char* path)
{
static version_t version, *r = NULL;
uint8_t* buf = NULL;
UINT uLen;
DWORD dwSize, dwHandle;
VS_FIXEDFILEINFO* version_info;
memset(&version, 0, sizeof(version));
dwSize = GetFileVersionInfoSizeU(path, &dwHandle);
if (dwSize == 0)
goto out;
buf = malloc(dwSize);
if (buf == NULL)
goto out;;
if (!GetFileVersionInfoU(path, dwHandle, dwSize, buf))
goto out;
if (!VerQueryValueA(buf, "\\", (LPVOID*)&version_info, &uLen) || uLen == 0)
goto out;
if (version_info->dwSignature != 0xfeef04bd)
goto out;
version.Major = (version_info->dwFileVersionMS >> 16) & 0xffff;
version.Minor = (version_info->dwFileVersionMS >> 0) & 0xffff;
version.Micro = (version_info->dwFileVersionLS >> 16) & 0xffff;
version.Nano = (version_info->dwFileVersionLS >> 0) & 0xffff;
r = &version;
out:
free(buf);
return r;
}
/*
@ -461,7 +544,7 @@ void StrArrayCreate(StrArray* arr, uint32_t initial_size)
arr->Max = initial_size; arr->Index = 0;
arr->String = (char**)calloc(arr->Max, sizeof(char*));
if (arr->String == NULL)
uprintf("Could not allocate string array\n");
uprintf("Could not allocate string array");
}
int32_t StrArrayAdd(StrArray* arr, const char* str, BOOL duplicate)
@ -475,13 +558,13 @@ int32_t StrArrayAdd(StrArray* arr, const char* str, BOOL duplicate)
arr->String = (char**)realloc(arr->String, arr->Max*sizeof(char*));
if (arr->String == NULL) {
free(old_table);
uprintf("Could not reallocate string array\n");
uprintf("Could not reallocate string array");
return -1;
}
}
arr->String[arr->Index] = (duplicate)?safe_strdup(str):(char*)str;
if (arr->String[arr->Index] == NULL) {
uprintf("Could not store string in array\n");
uprintf("Could not store string in array");
return -1;
}
return arr->Index++;
@ -504,7 +587,7 @@ void StrArrayClear(StrArray* arr)
uint32_t i;
if ((arr == NULL) || (arr->String == NULL))
return;
for (i=0; i<arr->Index; i++) {
for (i = 0; i < arr->Index; i++) {
safe_free(arr->String[i]);
}
arr->Index = 0;
@ -528,13 +611,13 @@ static PSID GetSID(void) {
char* psid_string = NULL;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token)) {
uprintf("OpenProcessToken failed: %s\n", WindowsErrorString());
uprintf("OpenProcessToken failed: %s", WindowsErrorString());
return NULL;
}
if (!GetTokenInformation(token, TokenUser, tu, 0, &len)) {
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
uprintf("GetTokenInformation (pre) failed: %s\n", WindowsErrorString());
uprintf("GetTokenInformation (pre) failed: %s", WindowsErrorString());
return NULL;
}
tu = (TOKEN_USER*)calloc(1, len);
@ -550,11 +633,11 @@ static PSID GetSID(void) {
* The workaround? Convert to string then back to PSID
*/
if (!ConvertSidToStringSidA(tu->User.Sid, &psid_string)) {
uprintf("Unable to convert SID to string: %s\n", WindowsErrorString());
uprintf("Unable to convert SID to string: %s", WindowsErrorString());
ret = NULL;
} else {
if (!ConvertStringSidToSidA(psid_string, &ret)) {
uprintf("Unable to convert string back to SID: %s\n", WindowsErrorString());
uprintf("Unable to convert string back to SID: %s", WindowsErrorString());
ret = NULL;
}
// MUST use LocalFree()
@ -562,7 +645,7 @@ static PSID GetSID(void) {
}
} else {
ret = NULL;
uprintf("GetTokenInformation (real) failed: %s\n", WindowsErrorString());
uprintf("GetTokenInformation (real) failed: %s", WindowsErrorString());
}
free(tu);
return ret;
@ -589,7 +672,7 @@ BOOL FileIO(enum file_io_type io_type, char* path, char** buffer, DWORD* size)
s_attr.lpSecurityDescriptor = &s_desc;
sa = &s_attr;
} else {
uprintf("Could not set security descriptor: %s\n", WindowsErrorString());
uprintf("Could not set security descriptor: %s", WindowsErrorString());
}
switch (io_type) {
@ -623,7 +706,7 @@ BOOL FileIO(enum file_io_type io_type, char* path, char** buffer, DWORD* size)
*size = GetFileSize(handle, NULL);
*buffer = (char*)malloc(*size);
if (*buffer == NULL) {
uprintf("Could not allocate buffer for reading file\n");
uprintf("Could not allocate buffer for reading file");
goto out;
}
r = ReadFile(handle, *buffer, *size, size, NULL);
@ -669,12 +752,12 @@ unsigned char* GetResource(HMODULE module, char* name, char* type, const char* d
res = FindResourceA(module, name, type);
if (res == NULL) {
uprintf("Could not locate resource '%s': %s\n", desc, WindowsErrorString());
uprintf("Could not locate resource '%s': %s", desc, WindowsErrorString());
goto out;
}
res_handle = LoadResource(module, res);
if (res_handle == NULL) {
uprintf("Could not load resource '%s': %s\n", desc, WindowsErrorString());
uprintf("Could not load resource '%s': %s", desc, WindowsErrorString());
goto out;
}
res_len = SizeofResource(module, res);
@ -684,12 +767,12 @@ unsigned char* GetResource(HMODULE module, char* name, char* type, const char* d
*len = res_len;
p = (unsigned char*)calloc(*len, 1);
if (p == NULL) {
uprintf("Could not allocate resource '%s'\n", desc);
uprintf("Could not allocate resource '%s'", desc);
goto out;
}
memcpy(p, LockResource(res_handle), min(res_len, *len));
if (res_len > *len)
uprintf("WARNING: Resource '%s' was truncated by %d bytes!\n", desc, res_len - *len);
uprintf("WARNING: Resource '%s' was truncated by %d bytes!", desc, res_len - *len);
} else {
p = (unsigned char*)LockResource(res_handle);
}
@ -706,14 +789,19 @@ DWORD GetResourceSize(HMODULE module, char* name, char* type, const char* desc)
}
// Run a console command, with optional redirection of stdout and stderr to our log
DWORD RunCommand(const char* cmd, const char* dir, BOOL log)
// as well as optional progress reporting if msg is not 0.
DWORD RunCommandWithProgress(const char* cmd, const char* dir, BOOL log, int msg)
{
DWORD ret, dwRead, dwAvail, dwPipeSize = 4096;
STARTUPINFOA si = {0};
PROCESS_INFORMATION pi = {0};
DWORD i, ret, dwRead, dwAvail, dwPipeSize = 4096;
STARTUPINFOA si = { 0 };
PROCESS_INFORMATION pi = { 0 };
SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
HANDLE hOutputRead = INVALID_HANDLE_VALUE, hOutputWrite = INVALID_HANDLE_VALUE;
int match_length;
static char* output;
// For detecting typical dism.exe commandline progress report of type:
// "\r[==== 8.0% ]\r\n"
re_t pattern = re_compile("\\s*\\[[= ]+[\\d\\.]+%[= ]+\\]\\s*");
si.cb = sizeof(si);
if (log) {
@ -737,16 +825,56 @@ DWORD RunCommand(const char* cmd, const char* dir, BOOL log)
goto out;
}
if (log) {
if (log || msg != 0) {
if (msg != 0)
UpdateProgressWithInfoInit(NULL, FALSE);
while (1) {
// Check for user cancel
if (IS_ERROR(FormatStatus) && (SCODE_CODE(FormatStatus) == ERROR_CANCELLED)) {
if (!TerminateProcess(pi.hProcess, ERROR_CANCELLED)) {
uprintf("Could not terminate command: %s", WindowsErrorString());
} else switch (WaitForSingleObject(pi.hProcess, 5000)) {
case WAIT_TIMEOUT:
uprintf("Command did not terminate within timeout duration");
break;
case WAIT_OBJECT_0:
uprintf("Command was terminated by user");
break;
default:
uprintf("Error while waiting for command to be terminated: %s", WindowsErrorString());
break;
}
ret = ERROR_CANCELLED;
goto out;
}
// coverity[string_null]
if (PeekNamedPipe(hOutputRead, NULL, dwPipeSize, NULL, &dwAvail, NULL)) {
if (dwAvail != 0) {
output = malloc(dwAvail + 1);
if ((output != NULL) && (ReadFile(hOutputRead, output, dwAvail, &dwRead, NULL)) && (dwRead != 0)) {
output[dwAvail] = 0;
// output may contain a '%' so don't feed it as a naked format string
uprintf("%s", output);
// Process a commandline progress bar into a percentage
if ((msg != 0) && (re_matchp(pattern, output, &match_length) != -1)) {
float f = 0.0f;
i = 0;
next_progress_line:
for (; (i < dwAvail) && (output[i] < '0' || output[i] > '9'); i++);
IGNORE_RETVAL(sscanf(&output[i], "%f*", &f));
UpdateProgressWithInfo(OP_FORMAT, msg, (uint64_t)(f * 100.0f), 100 * 100ULL);
// Go to next line
while ((++i < dwAvail) && (output[i] != '\n') && (output[i] != '\r'));
while ((++i < dwAvail) && ((output[i] == '\n') || (output[i] == '\r')));
// Print additional lines, if any
if (i < dwAvail) {
// Might have two consecutive progress lines in our buffer
if (re_matchp(pattern, &output[i], &match_length) != -1)
goto next_progress_line;
uprintf("%s", &output[i]);
}
} else if (log) {
// output may contain a '%' so don't feed it as a naked format string
uprintf("%s", output);
}
}
free(output);
}
@ -756,6 +884,7 @@ DWORD RunCommand(const char* cmd, const char* dir, BOOL log)
Sleep(100);
};
} else {
// TODO: Detect user cancellation here?
WaitForSingleObject(pi.hProcess, INFINITE);
}

View File

@ -1,7 +1,7 @@
/*
* Rufus: The Reliable USB Formatting Utility
* Standard User I/O Routines (logging, status, error, etc.)
* Copyright © 2011-2023 Pete Batard <pete@akeo.ie>
* Copyright © 2011-2024 Pete Batard <pete@akeo.ie>
* Copyright © 2020 Mattiwatti <mattiwatti@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
@ -27,25 +27,41 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <wininet.h>
#include <winternl.h>
#include <dbghelp.h>
#include <assert.h>
#include <ctype.h>
#include <math.h>
#include "rufus.h"
#include "missing.h"
#include "settings.h"
#include "resource.h"
#include "msapi_utf8.h"
#include "localization.h"
#define FACILITY_WIM 322
#define FACILITY_WIM 322
#define DEFAULT_BASE_ADDRESS 0x100000000ULL
#define RSDS_SIG 0x53445352
/*
* Globals
*/
const HANDLE hRufus = (HANDLE)0x0000005275667573ULL; // "\0\0\0Rufus"
HWND hStatus;
size_t ubuffer_pos = 0;
char ubuffer[UBUFFER_SIZE]; // Buffer for ubpushf() messages we don't log right away
#pragma pack(push, 1)
typedef struct {
DWORD Signature; // "RSDS"
GUID Guid;
DWORD Age;
CHAR PdbName[1];
} debug_info_t;
#pragma pack(pop)
void uprintf(const char *format, ...)
{
static char buf[4096];
@ -67,16 +83,15 @@ void uprintf(const char *format, ...)
*p++ = '\n';
*p = '\0';
// Yay, Windows 10 *FINALLY* added actual Unicode support for OutputDebugStringW()!
wbuf = utf8_to_wchar(buf);
// Send output to Windows debug facility
// coverity[dont_call]
OutputDebugStringW(wbuf);
if ((hLog != NULL) && (hLog != INVALID_HANDLE_VALUE)) {
// Send output to our log Window
Edit_SetSel(hLog, MAX_LOG_SIZE, MAX_LOG_SIZE);
Edit_ReplaceSel(hLog, wbuf);
// Make sure the message scrolls into view
// (Or see code commented in LogProc:WM_SHOWWINDOW for a less forceful scroll)
Edit_Scroll(hLog, Edit_GetLineCount(hLog), 0);
}
free(wbuf);
@ -86,6 +101,7 @@ void uprintfs(const char* str)
{
wchar_t* wstr;
wstr = utf8_to_wchar(str);
// coverity[dont_call]
OutputDebugStringW(wstr);
if ((hLog != NULL) && (hLog != INVALID_HANDLE_VALUE)) {
Edit_SetSel(hLog, MAX_LOG_SIZE, MAX_LOG_SIZE);
@ -204,472 +220,59 @@ void DumpBufferHex(void *buf, size_t size)
uprintf("%s\n", line);
}
// Count on Microsoft to add a new API while not bothering updating the existing error facilities,
// so that the new error messages have to be handled manually. Now, since I don't have all day:
// 1. Copy text from https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-vds/5102cc53-3143-4268-ba4c-6ea39e999ab4
// 2. awk '{l[NR%7]=$0} {if (NR%7==0) printf "\tcase %s:\t// %s\n\t\treturn \"%s\";\n", l[1], l[3], l[6]}' vds.txt
// 3. Filter out the crap we don't need.
static const char *GetVdsError(DWORD error_code)
{
switch (error_code) {
case 0x80042400: // VDS_E_NOT_SUPPORTED
return "The operation is not supported by the object.";
case 0x80042401: // VDS_E_INITIALIZED_FAILED
return "VDS or the provider failed to initialize.";
case 0x80042402: // VDS_E_INITIALIZE_NOT_CALLED
return "VDS did not call the hardware provider's initialization method.";
case 0x80042403: // VDS_E_ALREADY_REGISTERED
return "The provider is already registered.";
case 0x80042404: // VDS_E_ANOTHER_CALL_IN_PROGRESS
return "A concurrent second call is made on an object before the first call is completed.";
case 0x80042405: // VDS_E_OBJECT_NOT_FOUND
return "The specified object was not found.";
case 0x80042406: // VDS_E_INVALID_SPACE
return "The specified space is neither free nor valid.";
case 0x80042407: // VDS_E_PARTITION_LIMIT_REACHED
return "No more partitions can be created on the specified disk.";
case 0x80042408: // VDS_E_PARTITION_NOT_EMPTY
return "The extended partition is not empty.";
case 0x80042409: // VDS_E_OPERATION_PENDING
return "The operation is still in progress.";
case 0x8004240A: // VDS_E_OPERATION_DENIED
return "The operation is not permitted on the specified disk, partition, or volume.";
case 0x8004240B: // VDS_E_OBJECT_DELETED
return "The object no longer exists.";
case 0x8004240C: // VDS_E_CANCEL_TOO_LATE
return "The operation can no longer be canceled.";
case 0x8004240D: // VDS_E_OPERATION_CANCELED
return "The operation has already been canceled.";
case 0x8004240E: // VDS_E_CANNOT_EXTEND
return "The file system does not support extending this volume.";
case 0x8004240F: // VDS_E_NOT_ENOUGH_SPACE
return "There is not enough space to complete the operation.";
case 0x80042410: // VDS_E_NOT_ENOUGH_DRIVE
return "There are not enough free disk drives in the subsystem to complete the operation.";
case 0x80042411: // VDS_E_BAD_COOKIE
return "The cookie was not found.";
case 0x80042412: // VDS_E_NO_MEDIA
return "There is no removable media in the drive.";
case 0x80042413: // VDS_E_DEVICE_IN_USE
return "The device is currently in use.";
case 0x80042414: // VDS_E_DISK_NOT_EMPTY
return "The disk contains partitions or volumes.";
case 0x80042415: // VDS_E_INVALID_OPERATION
return "The specified operation is not valid.";
case 0x80042416: // VDS_E_PATH_NOT_FOUND
return "The specified path was not found.";
case 0x80042417: // VDS_E_DISK_NOT_INITIALIZED
return "The specified disk has not been initialized.";
case 0x80042418: // VDS_E_NOT_AN_UNALLOCATED_DISK
return "The specified disk is not an unallocated disk.";
case 0x80042419: // VDS_E_UNRECOVERABLE_ERROR
return "An unrecoverable error occurred. The service MUST shut down.";
case 0x0004241A: // VDS_S_DISK_PARTIALLY_CLEANED
return "The clean operation was not a full clean or was canceled before it could be completed.";
case 0x8004241B: // VDS_E_DMADMIN_SERVICE_CONNECTION_FAILED
return "The provider failed to connect to the LDMA service.";
case 0x8004241C: // VDS_E_PROVIDER_INITIALIZATION_FAILED
return "The provider failed to initialize.";
case 0x8004241D: // VDS_E_OBJECT_EXISTS
return "The object already exists.";
case 0x8004241E: // VDS_E_NO_DISKS_FOUND
return "No disks were found on the target machine.";
case 0x8004241F: // VDS_E_PROVIDER_CACHE_CORRUPT
return "The cache for a provider is corrupt.";
case 0x80042420: // VDS_E_DMADMIN_METHOD_CALL_FAILED
return "A method call to the LDMA service failed.";
case 0x00042421: // VDS_S_PROVIDER_ERROR_LOADING_CACHE
return "The provider encountered errors while loading the cache.";
case 0x80042422: // VDS_E_PROVIDER_VOL_DEVICE_NAME_NOT_FOUND
return "The device form of the volume pathname could not be retrieved.";
case 0x80042423: // VDS_E_PROVIDER_VOL_OPEN
return "Failed to open the volume device";
case 0x80042424: // VDS_E_DMADMIN_CORRUPT_NOTIFICATION
return "A corrupt notification was sent from the LDMA service.";
case 0x80042425: // VDS_E_INCOMPATIBLE_FILE_SYSTEM
return "The file system is incompatible with the specified operation.";
case 0x80042426: // VDS_E_INCOMPATIBLE_MEDIA
return "The media is incompatible with the specified operation.";
case 0x80042427: // VDS_E_ACCESS_DENIED
return "Access is denied. A VDS operation MUST run elevated.";
case 0x80042428: // VDS_E_MEDIA_WRITE_PROTECTED
return "The media is write-protected.";
case 0x80042429: // VDS_E_BAD_LABEL
return "The volume label is not valid.";
case 0x8004242A: // VDS_E_CANT_QUICK_FORMAT
return "The volume cannot be quick-formatted.";
case 0x8004242B: // VDS_E_IO_ERROR
return "An I/O error occurred during the operation.";
case 0x8004242C: // VDS_E_VOLUME_TOO_SMALL
return "The volume size is too small.";
case 0x8004242D: // VDS_E_VOLUME_TOO_BIG
return "The volume size is too large.";
case 0x8004242E: // VDS_E_CLUSTER_SIZE_TOO_SMALL
return "The cluster size is too small.";
case 0x8004242F: // VDS_E_CLUSTER_SIZE_TOO_BIG
return "The cluster size is too large.";
case 0x80042430: // VDS_E_CLUSTER_COUNT_BEYOND_32BITS
return "The number of clusters is too large to be represented as a 32-bit integer.";
case 0x80042431: // VDS_E_OBJECT_STATUS_FAILED
return "The component that the object represents has failed.";
case 0x80042432: // VDS_E_VOLUME_INCOMPLETE
return "The volume is incomplete.";
case 0x80042433: // VDS_E_EXTENT_SIZE_LESS_THAN_MIN
return "The specified extent size is too small.";
case 0x00042434: // VDS_S_UPDATE_BOOTFILE_FAILED
return "The operation was successful, but VDS failed to update the boot options.";
case 0x00042436: // VDS_S_BOOT_PARTITION_NUMBER_CHANGE
case 0x80042436: // VDS_E_BOOT_PARTITION_NUMBER_CHANGE
return "The boot partition's partition number will change as a result of the operation.";
case 0x80042437: // VDS_E_NO_FREE_SPACE
return "The specified disk does not have enough free space to complete the operation.";
case 0x80042438: // VDS_E_ACTIVE_PARTITION
return "An active partition was detected on the selected disk.";
case 0x80042439: // VDS_E_PARTITION_OF_UNKNOWN_TYPE
return "The partition information cannot be read.";
case 0x8004243A: // VDS_E_LEGACY_VOLUME_FORMAT
return "A partition with an unknown type was detected on the specified disk.";
case 0x8004243C: // VDS_E_MIGRATE_OPEN_VOLUME
return "A volume on the specified disk could not be opened.";
case 0x8004243D: // VDS_E_VOLUME_NOT_ONLINE
return "The volume is not online.";
case 0x8004243E: // VDS_E_VOLUME_NOT_HEALTHY
return "The volume is failing or has failed.";
case 0x8004243F: // VDS_E_VOLUME_SPANS_DISKS
return "The volume spans multiple disks.";
case 0x80042440: // VDS_E_REQUIRES_CONTIGUOUS_DISK_SPACE
return "The volume does not consist of a single disk extent.";
case 0x80042441: // VDS_E_BAD_PROVIDER_DATA
return "A provider returned bad data.";
case 0x80042442: // VDS_E_PROVIDER_FAILURE
return "A provider failed to complete an operation.";
case 0x00042443: // VDS_S_VOLUME_COMPRESS_FAILED
return "The file system was formatted successfully but could not be compressed.";
case 0x80042444: // VDS_E_PACK_OFFLINE
return "The pack is offline.";
case 0x80042445: // VDS_E_VOLUME_NOT_A_MIRROR
return "The volume is not a mirror.";
case 0x80042446: // VDS_E_NO_EXTENTS_FOR_VOLUME
return "No extents were found for the volume.";
case 0x80042447: // VDS_E_DISK_NOT_LOADED_TO_CACHE
return "The migrated disk failed to load to the cache.";
case 0x80042448: // VDS_E_INTERNAL_ERROR
return "VDS encountered an internal error.";
case 0x8004244A: // VDS_E_PROVIDER_TYPE_NOT_SUPPORTED
return "The method call is not supported for the specified provider type.";
case 0x8004244B: // VDS_E_DISK_NOT_ONLINE
return "One or more of the specified disks are not online.";
case 0x8004244C: // VDS_E_DISK_IN_USE_BY_VOLUME
return "One or more extents of the disk are already being used by the volume.";
case 0x0004244D: // VDS_S_IN_PROGRESS
return "The asynchronous operation is in progress.";
case 0x8004244E: // VDS_E_ASYNC_OBJECT_FAILURE
return "Failure initializing the asynchronous object.";
case 0x8004244F: // VDS_E_VOLUME_NOT_MOUNTED
return "The volume is not mounted.";
case 0x80042450: // VDS_E_PACK_NOT_FOUND
return "The pack was not found.";
case 0x80042453: // VDS_E_OBJECT_OUT_OF_SYNC
return "The reference to the object might be stale.";
case 0x80042454: // VDS_E_MISSING_DISK
return "The specified disk could not be found.";
case 0x80042455: // VDS_E_DISK_PNP_REG_CORRUPT
return "The provider's list of PnP registered disks has become corrupted.";
case 0x80042457: // VDS_E_NO_DRIVELETTER_FLAG
return "The provider does not support the VDS_VF_NO DRIVELETTER volume flag.";
case 0x80042459: // VDS_E_REVERT_ON_CLOSE_SET
return "Some volume flags are already set.";
case 0x0004245B: // VDS_S_UNABLE_TO_GET_GPT_ATTRIBUTES
return "Unable to retrieve the GPT attributes for this volume.";
case 0x8004245C: // VDS_E_VOLUME_TEMPORARILY_DISMOUNTED
return "The volume is already dismounted temporarily.";
case 0x8004245D: // VDS_E_VOLUME_PERMANENTLY_DISMOUNTED
return "The volume is already permanently dismounted.";
case 0x8004245E: // VDS_E_VOLUME_HAS_PATH
return "The volume cannot be dismounted permanently because it still has an access path.";
case 0x8004245F: // VDS_E_TIMEOUT
return "The operation timed out.";
case 0x80042461: // VDS_E_LDM_TIMEOUT
return "The operation timed out in the LDMA service. Retry the operation.";
case 0x80042462: // VDS_E_REVERT_ON_CLOSE_MISMATCH
return "The flags to be cleared do not match the flags that were set previously.";
case 0x80042463: // VDS_E_RETRY
return "The operation failed. Retry the operation.";
case 0x80042464: // VDS_E_ONLINE_PACK_EXISTS
return "The operation failed, because an online pack object already exists.";
case 0x80042468: // VDS_E_MAX_USABLE_MBR
return "Only the first 2TB are usable on large MBR disks.";
case 0x80042500: // VDS_E_NO_SOFTWARE_PROVIDERS_LOADED
return "There are no software providers loaded.";
case 0x80042501: // VDS_E_DISK_NOT_MISSING
return "The disk is not missing.";
case 0x80042502: // VDS_E_NO_VOLUME_LAYOUT
return "The volume's layout could not be retrieved.";
case 0x80042503: // VDS_E_CORRUPT_VOLUME_INFO
return "The volume's driver information is corrupted.";
case 0x80042504: // VDS_E_INVALID_ENUMERATOR
return "The enumerator is corrupted";
case 0x80042505: // VDS_E_DRIVER_INTERNAL_ERROR
return "An internal error occurred in the volume management driver.";
case 0x80042507: // VDS_E_VOLUME_INVALID_NAME
return "The volume name is not valid.";
case 0x00042508: // VDS_S_DISK_IS_MISSING
return "The disk is missing and not all information could be returned.";
case 0x80042509: // VDS_E_CORRUPT_PARTITION_INFO
return "The disk's partition information is corrupted.";
case 0x0004250A: // VDS_S_NONCONFORMANT_PARTITION_INFO
return "The disk's partition information does not conform to what is expected on a dynamic disk.";
case 0x8004250B: // VDS_E_CORRUPT_EXTENT_INFO
return "The disk's extent information is corrupted.";
case 0x0004250E: // VDS_S_SYSTEM_PARTITION
return "Warning: There was a failure while checking for the system partition.";
case 0x8004250F: // VDS_E_BAD_PNP_MESSAGE
return "The PNP service sent a corrupted notification to the provider.";
case 0x80042510: // VDS_E_NO_PNP_DISK_ARRIVE
case 0x80042511: // VDS_E_NO_PNP_VOLUME_ARRIVE
return "No disk/volume arrival notification was received.";
case 0x80042512: // VDS_E_NO_PNP_DISK_REMOVE
case 0x80042513: // VDS_E_NO_PNP_VOLUME_REMOVE
return "No disk/volume removal notification was received.";
case 0x80042514: // VDS_E_PROVIDER_EXITING
return "The provider is exiting.";
case 0x00042517: // VDS_S_NO_NOTIFICATION
return "No volume arrival notification was received.";
case 0x80042519: // VDS_E_INVALID_DISK
return "The specified disk is not valid.";
case 0x8004251A: // VDS_E_INVALID_PACK
return "The specified disk pack is not valid.";
case 0x8004251B: // VDS_E_VOLUME_ON_DISK
return "This operation is not allowed on disks with volumes.";
case 0x8004251C: // VDS_E_DRIVER_INVALID_PARAM
return "The driver returned an invalid parameter error.";
case 0x8004253D: // VDS_E_DRIVER_OBJECT_NOT_FOUND
return "The object was not found in the driver cache.";
case 0x8004253E: // VDS_E_PARTITION_NOT_CYLINDER_ALIGNED
return "The disk layout contains partitions which are not cylinder aligned.";
case 0x8004253F: // VDS_E_DISK_LAYOUT_PARTITIONS_TOO_SMALL
return "The disk layout contains partitions which are less than the minimum required size.";
case 0x80042540: // VDS_E_DISK_IO_FAILING
return "The I/O to the disk is failing.";
case 0x80042543: // VDS_E_GPT_ATTRIBUTES_INVALID
return "Invalid GPT attributes were specified.";
case 0x8004254D: // VDS_E_UNEXPECTED_DISK_LAYOUT_CHANGE
return "An unexpected layout change occurred external to the volume manager.";
case 0x8004254E: // VDS_E_INVALID_VOLUME_LENGTH
return "The volume length is invalid.";
case 0x8004254F: // VDS_E_VOLUME_LENGTH_NOT_SECTOR_SIZE_MULTIPLE
return "The volume length is not a multiple of the sector size.";
case 0x80042550: // VDS_E_VOLUME_NOT_RETAINED
return "The volume does not have a retained partition association.";
case 0x80042551: // VDS_E_VOLUME_RETAINED
return "The volume already has a retained partition association.";
case 0x80042553: // VDS_E_ALIGN_BEYOND_FIRST_CYLINDER
return "The specified alignment is beyond the first cylinder.";
case 0x80042554: // VDS_E_ALIGN_NOT_SECTOR_SIZE_MULTIPLE
return "The specified alignment is not a multiple of the sector size.";
case 0x80042555: // VDS_E_ALIGN_NOT_ZERO
return "The specified partition type cannot be created with a non-zero alignment.";
case 0x80042556: // VDS_E_CACHE_CORRUPT
return "The service's cache has become corrupt.";
case 0x80042557: // VDS_E_CANNOT_CLEAR_VOLUME_FLAG
return "The specified volume flag cannot be cleared.";
case 0x80042558: // VDS_E_DISK_BEING_CLEANED
return "The operation is not allowed on a disk that is in the process of being cleaned.";
case 0x8004255A: // VDS_E_DISK_REMOVEABLE
return "The operation is not supported on removable media.";
case 0x8004255B: // VDS_E_DISK_REMOVEABLE_NOT_EMPTY
return "The operation is not supported on a non-empty removable disk.";
case 0x8004255C: // VDS_E_DRIVE_LETTER_NOT_FREE
return "The specified drive letter is not free to be assigned.";
case 0x8004255E: // VDS_E_INVALID_DRIVE_LETTER
return "The specified drive letter is not valid.";
case 0x8004255F: // VDS_E_INVALID_DRIVE_LETTER_COUNT
return "The specified number of drive letters to retrieve is not valid.";
case 0x80042560: // VDS_E_INVALID_FS_FLAG
return "The specified file system flag is not valid.";
case 0x80042561: // VDS_E_INVALID_FS_TYPE
return "The specified file system is not valid.";
case 0x80042562: // VDS_E_INVALID_OBJECT_TYPE
return "The specified object type is not valid.";
case 0x80042563: // VDS_E_INVALID_PARTITION_LAYOUT
return "The specified partition layout is invalid.";
case 0x80042564: // VDS_E_INVALID_PARTITION_STYLE
return "VDS only supports MBR or GPT partition style disks.";
case 0x80042565: // VDS_E_INVALID_PARTITION_TYPE
return "The specified partition type is not valid for this operation.";
case 0x80042566: // VDS_E_INVALID_PROVIDER_CLSID
case 0x80042567: // VDS_E_INVALID_PROVIDER_ID
case 0x8004256A: // VDS_E_INVALID_PROVIDER_VERSION_GUID
return "A NULL GUID was passed to the provider.";
case 0x80042568: // VDS_E_INVALID_PROVIDER_NAME
return "The specified provider name is invalid.";
case 0x80042569: // VDS_E_INVALID_PROVIDER_TYPE
return "The specified provider type is invalid.";
case 0x8004256B: // VDS_E_INVALID_PROVIDER_VERSION_STRING
return "The specified provider version string is invalid.";
case 0x8004256C: // VDS_E_INVALID_QUERY_PROVIDER_FLAG
return "The specified query provider flag is invalid.";
case 0x8004256D: // VDS_E_INVALID_SERVICE_FLAG
return "The specified service flag is invalid.";
case 0x8004256E: // VDS_E_INVALID_VOLUME_FLAG
return "The specified volume flag is invalid.";
case 0x8004256F: // VDS_E_PARTITION_NOT_OEM
return "The operation is only supported on an OEM, ESP, or unknown partition.";
case 0x80042570: // VDS_E_PARTITION_PROTECTED
return "Cannot delete a protected partition without the force protected parameter set.";
case 0x80042571: // VDS_E_PARTITION_STYLE_MISMATCH
return "The specified partition style is not the same as the disk's partition style.";
case 0x80042572: // VDS_E_PROVIDER_INTERNAL_ERROR
return "An internal error has occurred in the provider.";
case 0x80042575: // VDS_E_UNRECOVERABLE_PROVIDER_ERROR
return "An unrecoverable error occurred in the provider.";
case 0x80042576: // VDS_E_VOLUME_HIDDEN
return "Cannot assign a mount point to a hidden volume.";
case 0x00042577: // VDS_S_DISMOUNT_FAILED
case 0x00042578: // VDS_S_REMOUNT_FAILED
return "Failed to dismount/remount the volume after setting the volume flags.";
case 0x80042579: // VDS_E_FLAG_ALREADY_SET
return "Cannot set the specified flag as revert-on-close because it is already set.";
case 0x8004257B: // VDS_E_DISTINCT_VOLUME
return "The input volume id cannot be the id of the volume that is the target of the operation.";
case 0x00042583: // VDS_S_FS_LOCK
return "Failed to obtain a file system lock.";
case 0x80042584: // VDS_E_READONLY
return "The volume is read only.";
case 0x80042585: // VDS_E_INVALID_VOLUME_TYPE
return "The volume type is invalid for this operation.";
case 0x80042588: // VDS_E_VOLUME_MIRRORED
return "This operation is not supported on a mirrored volume.";
case 0x80042589: // VDS_E_VOLUME_SIMPLE_SPANNED
return "The operation is only supported on simple or spanned volumes.";
case 0x8004258C: // VDS_E_PARTITION_MSR
case 0x8004258D: // VDS_E_PARTITION_LDM
return "The operation is not supported on this type of partitions.";
case 0x0004258E: // VDS_S_WINPE_BOOTENTRY
return "The boot entries cannot be updated automatically on WinPE.";
case 0x8004258F: // VDS_E_ALIGN_NOT_A_POWER_OF_TWO
return "The alignment is not a power of two.";
case 0x80042590: // VDS_E_ALIGN_IS_ZERO
return "The alignment is zero.";
case 0x80042593: // VDS_E_FS_NOT_DETERMINED
return "The default file system could not be determined.";
case 0x80042595: // VDS_E_DISK_NOT_OFFLINE
return "This disk is already online.";
case 0x80042596: // VDS_E_FAILED_TO_ONLINE_DISK
return "The online operation failed.";
case 0x80042597: // VDS_E_FAILED_TO_OFFLINE_DISK
return "The offline operation failed.";
case 0x80042598: // VDS_E_BAD_REVISION_NUMBER
return "The operation could not be completed because the specified revision number is not supported.";
case 0x00042700: // VDS_S_NAME_TRUNCATED
return "The name was set successfully but had to be truncated.";
case 0x80042701: // VDS_E_NAME_NOT_UNIQUE
return "The specified name is not unique.";
case 0x8004270F: // VDS_E_NO_DISK_PATHNAME
return "The disk's path could not be retrieved. Some operations on the disk might fail.";
case 0x80042711: // VDS_E_NO_VOLUME_PATHNAME
return "The path could not be retrieved for one or more volumes.";
case 0x80042712: // VDS_E_PROVIDER_CACHE_OUTOFSYNC
return "The provider's cache is not in sync with the driver cache.";
case 0x80042713: // VDS_E_NO_IMPORT_TARGET
return "No import target was set for the subsystem.";
case 0x00042714: // VDS_S_ALREADY_EXISTS
return "The object already exists.";
case 0x00042715: // VDS_S_PROPERTIES_INCOMPLETE
return "Some, but not all, of the properties were successfully retrieved.";
case 0x80042803: // VDS_E_UNABLE_TO_FIND_BOOT_DISK
return "Volume disk extent information could not be retrieved for the boot volume.";
case 0x80042807: // VDS_E_BOOT_DISK
return "Disk attributes cannot be changed on the boot disk.";
case 0x00042808: // VDS_S_DISK_MOUNT_FAILED
case 0x00042809: // VDS_S_DISK_DISMOUNT_FAILED
return "One or more of the volumes on the disk could not be mounted/dismounted.";
case 0x8004280A: // VDS_E_DISK_IS_OFFLINE
case 0x8004280B: // VDS_E_DISK_IS_READ_ONLY
return "The operation cannot be performed on a disk that is offline or read-only.";
case 0x8004280C: // VDS_E_PAGEFILE_DISK
case 0x8004280D: // VDS_E_HIBERNATION_FILE_DISK
case 0x8004280E: // VDS_E_CRASHDUMP_DISK
return "The operation cannot be performed on a disk that contains a pagefile, hibernation or crashdump volume.";
case 0x8004280F: // VDS_E_UNABLE_TO_FIND_SYSTEM_DISK
return "A system error occurred while retrieving the system disk information.";
case 0x80042810: // VDS_E_INCORRECT_SYSTEM_VOLUME_EXTENT_INFO
return "Multiple disk extents reported for the system volume - system error.";
case 0x80042811: // VDS_E_SYSTEM_DISK
return "Disk attributes cannot be changed on the current system disk or BIOS disk 0.";
case 0x80042823: // VDS_E_SECTOR_SIZE_ERROR
return "The sector size MUST be non-zero, a power of 2, and less than the maximum sector size.";
case 0x80042907: // VDS_E_SUBSYSTEM_ID_IS_NULL
return "The provider returned a NULL subsystem identification string.";
case 0x8004290C: // VDS_E_REBOOT_REQUIRED
return "A reboot is required before any further operations are initiated.";
case 0x8004290D: // VDS_E_VOLUME_GUID_PATHNAME_NOT_ALLOWED
return "Volume GUID pathnames are not valid input to this method.";
case 0x8004290E: // VDS_E_BOOT_PAGEFILE_DRIVE_LETTER
return "Assigning or removing drive letters on the current boot or pagefile volume is not allowed.";
case 0x8004290F: // VDS_E_DELETE_WITH_CRITICAL
return "Delete is not allowed on a critical volume.";
case 0x80042910: // VDS_E_CLEAN_WITH_DATA
case 0x80042911: // VDS_E_CLEAN_WITH_OEM
return "The FORCE parameter MUST be set to TRUE in order to clean a disk that contains a data or OEM volume.";
case 0x80042912: // VDS_E_CLEAN_WITH_CRITICAL
return "Clean is not allowed on a critical disk.";
case 0x80042913: // VDS_E_FORMAT_CRITICAL
return "Format is not allowed on a critical volume.";
case 0x80042914: // VDS_E_NTFS_FORMAT_NOT_SUPPORTED
case 0x80042915: // VDS_E_FAT32_FORMAT_NOT_SUPPORTED
case 0x80042916: // VDS_E_FAT_FORMAT_NOT_SUPPORTED
return "The requested file system format is not supported on this volume.";
case 0x80042917: // VDS_E_FORMAT_NOT_SUPPORTED
return "The volume is not formattable.";
case 0x80042918: // VDS_E_COMPRESSION_NOT_SUPPORTED
return "The specified file system does not support compression.";
default:
return NULL;
}
}
static const char* GetVimError(DWORD error_code)
{
switch (error_code) {
case 0xC1420127:
return "The specified image in the specified wim is already mounted for read and write access.";
default:
return NULL;
}
}
// Convert a windows error to human readable string
// Convert a Windows error to human readable string
// One really has to wonder why the hell FormatMessage() was designed not to
// handle FORMAT_MESSAGE_FROM_HMODULE automatically according to the facility...
const char *WindowsErrorString(void)
{
static char err_string[256] = { 0 };
DWORD size, presize;
DWORD error_code, format_error;
HANDLE hModule = NULL;
error_code = GetLastError();
// Check for VDS error codes
if ((HRESULT_FACILITY(error_code) == FACILITY_ITF) && (GetVdsError(error_code) != NULL)) {
static_sprintf(err_string, "[0x%08lX] %s", error_code, GetVdsError(error_code));
return err_string;
}
if ((HRESULT_FACILITY(error_code) == FACILITY_WIM) && (GetVimError(error_code) != NULL)) {
static_sprintf(err_string, "[0x%08lX] %s", error_code, GetVimError(error_code));
return err_string;
// Check for specific facility error codes
switch (HRESULT_FACILITY(error_code)) {
case FACILITY_NULL:
// Special case for internet related errors, that don't actually have a facility
// set but still require a hModule into wininet to display the messages.
if ((error_code >= INTERNET_ERROR_BASE) && (error_code <= INTERNET_ERROR_LAST))
hModule = GetModuleHandleA("wininet.dll");
break;
case FACILITY_ITF:
hModule = GetModuleHandleA("vdsutil.dll");
break;
case FACILITY_WIM:
hModule = GetModuleHandleA("wimgapi.dll");
break;
default:
break;
}
static_sprintf(err_string, "[0x%08lX] ", error_code);
presize = (DWORD)strlen(err_string);
size = FormatMessageU(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, NULL,
// coverity[var_deref_model]
size = FormatMessageU(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS |
((hModule != NULL) ? FORMAT_MESSAGE_FROM_HMODULE : 0), hModule,
HRESULT_CODE(error_code), MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
&err_string[presize], (DWORD)(sizeof(err_string)-strlen(err_string)), NULL);
if (size == 0) {
format_error = GetLastError();
if ((format_error) && (format_error != ERROR_MR_MID_NOT_FOUND) && (format_error != ERROR_MUI_FILE_NOT_LOADED))
static_sprintf(err_string, "Windows error code 0x%08lX (FormatMessage error code 0x%08lX)",
switch (format_error) {
case ERROR_SUCCESS:
static_sprintf(err_string, "[0x%08lX] (No Windows Error String)", error_code);
break;
case ERROR_MR_MID_NOT_FOUND:
case ERROR_MUI_FILE_NOT_FOUND:
case ERROR_MUI_FILE_NOT_LOADED:
static_sprintf(err_string, "[0x%08lX] (NB: This system was unable to provide an English error message)", error_code);
break;
default:
static_sprintf(err_string, "[0x%08lX] (FormatMessage error code 0x%08lX)",
error_code, format_error);
else
static_sprintf(err_string, "Windows error code 0x%08lX", error_code);
break;
}
} else {
// Microsoft may suffix CRLF to error messages, which we need to remove...
assert(presize > 2);
@ -683,12 +286,13 @@ const char *WindowsErrorString(void)
return err_string;
}
char* GuidToString(const GUID* guid)
char* GuidToString(const GUID* guid, BOOL bDecorated)
{
static char guid_string[MAX_GUID_STRING_LENGTH];
if (guid == NULL) return NULL;
sprintf(guid_string, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
sprintf(guid_string, bDecorated ? "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}" :
"%08X%04X%04X%02X%02X%02X%02X%02X%02X%02X%02X",
(uint32_t)guid->Data1, guid->Data2, guid->Data3,
guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
@ -967,8 +571,8 @@ BOOL WriteFileWithRetry(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWr
break;
if (nTry < nNumRetries) {
uprintf("Retrying in %d seconds...", WRITE_TIMEOUT / 1000);
// Don't sit idly but use the downtime to check for conflicting processes...
Sleep(CheckDriveAccess(WRITE_TIMEOUT, FALSE));
// TODO: Call GetProcessSearch() here?
Sleep(WRITE_TIMEOUT);
}
}
if (SCODE_CODE(GetLastError()) == ERROR_SUCCESS)
@ -1013,7 +617,7 @@ DWORD WaitForSingleObjectWithMessages(HANDLE hHandle, DWORD dwMilliseconds)
}
#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
#define STATUS_NOT_IMPLEMENTED ((NTSTATUS)0xC0000002L)
#define STATUS_PROCEDURE_NOT_FOUND ((NTSTATUS)0xC000007AL)
#define FILE_ATTRIBUTE_VALID_FLAGS 0x00007FB7
#define NtCurrentPeb() (NtCurrentTeb()->ProcessEnvironmentBlock)
#define RtlGetProcessHeap() (NtCurrentPeb()->Reserved4[1]) // NtCurrentPeb()->ProcessHeap, mangled due to deficiencies in winternl.h
@ -1143,3 +747,138 @@ HANDLE CreatePreallocatedFile(const char* lpFileName, DWORD dwDesiredAccess,
return fileHandle;
}
// The following calls are used to resolve the addresses of DLL function calls
// that are not publicly exposed by Microsoft. This is accomplished by downloading
// the relevant .pdb and looking up the relevant address there. Once an address is
// found, it is stored in the Rufus settings so that it can be reused.
PF_TYPE_DECL(WINAPI, BOOL, SymInitialize, (HANDLE, PCSTR, BOOL));
PF_TYPE_DECL(WINAPI, DWORD64, SymLoadModuleEx, (HANDLE, HANDLE, PCSTR, PCSTR, DWORD64, DWORD, PMODLOAD_DATA, DWORD));
PF_TYPE_DECL(WINAPI, BOOL, SymUnloadModule64, (HANDLE, DWORD64));
PF_TYPE_DECL(WINAPI, BOOL, SymEnumSymbols, (HANDLE, ULONG64, PCSTR, PSYM_ENUMERATESYMBOLS_CALLBACK, PVOID));
PF_TYPE_DECL(WINAPI, BOOL, SymCleanup, (HANDLE));
BOOL CALLBACK EnumSymProc(PSYMBOL_INFO pSymInfo, ULONG SymbolSize, PVOID UserContext)
{
dll_resolver_t* resolver = (dll_resolver_t*)UserContext;
uint32_t i;
for (i = 0; i < resolver->count; i++) {
if (safe_strcmp(pSymInfo->Name, resolver->name[i]) == 0) {
resolver->address[i] = (uint32_t)pSymInfo->Address;
#if defined(_DEBUG)
uprintf("%08x: %s", resolver->address[i], resolver->name[i]);
#endif
}
}
return TRUE;
}
uint32_t ResolveDllAddress(dll_resolver_t* resolver)
{
uint32_t r = 0;
uint32_t i;
debug_info_t* info = NULL;
char url[MAX_PATH], saved_id[MAX_PATH], path[MAX_PATH];
uint8_t* buf = NULL;
DWORD* dbuf;
DWORD64 base_address = 0ULL;
PF_INIT(SymInitialize, DbgHelp);
PF_INIT(SymLoadModuleEx, DbgHelp);
PF_INIT(SymUnloadModule64, DbgHelp);
PF_INIT(SymEnumSymbols, DbgHelp);
PF_INIT(SymCleanup, DbgHelp);
if (pfSymInitialize == NULL || pfSymLoadModuleEx == NULL || pfSymUnloadModule64 == NULL ||
pfSymEnumSymbols == NULL || pfSymCleanup == NULL || resolver->count == 0 ||
resolver->path == NULL || resolver->name == NULL || resolver->address == NULL)
return 0;
// Get the PDB unique address from the DLL. Note that we can *NOT* use SymGetModuleInfo64() to
// obtain the data we need because Microsoft either *BOTCHED* or *DELIBERATELY CRIPPLED* their
// SymLoadModuleEx()/SymLoadModule64() implementation on ARM64, so that the return value is always
// 0 with GetLastError() set to ERROR_SUCCESS, thereby *FALSELY* indicating that the module is
// already loaded... So we just load the whole DLL into a buffer and look for an "RSDS" section
// per https://www.godevtool.com/Other/pdb.htm
r = read_file(resolver->path, &buf);
if (r == 0)
return 0;
dbuf = (DWORD*)buf;
for (i = 0; i < (r - sizeof(debug_info_t)) / sizeof(DWORD); i++) {
if (dbuf[i] == RSDS_SIG) {
info = (debug_info_t*)&dbuf[i];
if (safe_strstr(info->PdbName, ".pdb") != NULL)
break;
}
}
if (info == NULL) {
uprintf("Could not find debug info in '%s'", resolver->path);
goto out;
}
// Check settings to see if we have existing data for these DLL calls.
for (i = 0; i < resolver->count; i++) {
static_sprintf(saved_id, "%s@%s%x:%s", _filenameU(resolver->path),
GuidToString(&info->Guid, FALSE), (int)info->Age, resolver->name[i]);
resolver->address[i] = ReadSetting32(saved_id);
if (resolver->address[i] == 0)
break;
}
if (i == resolver->count) {
// No need to download the PDB
r = resolver->count;
goto out;
}
// Download the PDB from Microsoft's symbol servers
if (MessageBoxExU(hMainDialog, lmprintf(MSG_345), lmprintf(MSG_115),
MB_YESNO | MB_ICONWARNING | MB_IS_RTL, selected_langid) != IDYES)
goto out;
static_sprintf(path, "%s\\%s", temp_dir, info->PdbName);
static_sprintf(url, "http://msdl.microsoft.com/download/symbols/%s/%s%x/%s",
info->PdbName, GuidToString(&info->Guid, FALSE), (int)info->Age, info->PdbName);
if (DownloadToFileOrBufferEx(url, path, SYMBOL_SERVER_USER_AGENT, NULL, hMainDialog, FALSE) < 200 * KB)
goto out;
if (!pfSymInitialize(hRufus, NULL, FALSE)) {
uprintf("Could not initialize DLL symbol handler");
goto out;
}
// NB: SymLoadModuleEx() does not load a PDB unless the file has an explicit '.pdb' extension
base_address = pfSymLoadModuleEx(hRufus, NULL, path, NULL, DEFAULT_BASE_ADDRESS, 0, NULL, 0);
assert(base_address == DEFAULT_BASE_ADDRESS);
// On Windows 11 ARM64 the following call will return *TWO* different addresses for the same
// call, because most Windows DLL's are ARM64X, which means that they are an unholy union of
// both X64 and ARM64 code in the same binary...
// See https://learn.microsoft.com/en-us/windows/arm/arm64x-pe
// Now this would be all swell and dandy if Microsoft's debugging/symbol APIs had followed
// and would give us a hint of the architecture behind each duplicate address, but of course,
// the SYMBOL_INFO passed to EnumSymProc contains no such data. So we currently don't have a
// way to tell which of the two addresses we get on ARM64 is for which architecture... :(
pfSymEnumSymbols(hRufus, base_address, "*!*", EnumSymProc, resolver);
DeleteFileU(path);
// Store the addresses
r = 0;
for (i = 0; i < resolver->count; i++) {
static_sprintf(saved_id, "%s@%s%x:%s", _filenameU(resolver->path),
GuidToString(&info->Guid, FALSE), (int)info->Age, resolver->name[i]);
if (resolver->address[i] != 0) {
WriteSetting32(saved_id, resolver->address[i]);
r++;
}
}
out:
free(buf);
if (base_address != 0)
pfSymUnloadModule64(hRufus, base_address);
pfSymCleanup(hRufus);
return r;
}

View File

@ -1,7 +1,7 @@
/*
* Rufus: The Reliable USB Formatting Utility
* Standard Dialog Routines (Browse for folder, About, etc)
* Copyright © 2011-2023 Pete Batard <pete@akeo.ie>
* Copyright © 2011-2024 Pete Batard <pete@akeo.ie>
*
* 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
@ -90,14 +90,9 @@ void SetDialogFocus(HWND hDlg, HWND hCtrl)
* *EACH* thread you invoke FileDialog from, as GetDisplayName() will
* return error 0x8001010E otherwise.
*/
char* FileDialog(BOOL save, char* path, const ext_t* ext, DWORD options)
char* FileDialog(BOOL save, char* path, const ext_t* ext, UINT* selected_ext)
{
DWORD tmp;
OPENFILENAMEA ofn;
char selected_name[MAX_PATH];
char *ext_string = NULL, *all_files = NULL;
size_t i, j, ext_strlen;
BOOL r;
size_t i;
char* filepath = NULL;
HRESULT hr = FALSE;
IFileDialog *pfd = NULL;
@ -108,167 +103,109 @@ char* FileDialog(BOOL save, char* path, const ext_t* ext, DWORD options)
if ((ext == NULL) || (ext->count == 0) || (ext->extension == NULL) || (ext->description == NULL))
return NULL;
dialog_showing++;
filter_spec = (COMDLG_FILTERSPEC*)calloc(ext->count + 1, sizeof(COMDLG_FILTERSPEC));
if (filter_spec != NULL) {
// Setup the file extension filter table
for (i = 0; i < ext->count; i++) {
filter_spec[i].pszSpec = utf8_to_wchar(ext->extension[i]);
filter_spec[i].pszName = utf8_to_wchar(ext->description[i]);
}
filter_spec[i].pszSpec = L"*.*";
filter_spec[i].pszName = utf8_to_wchar(lmprintf(MSG_107));
if (filter_spec == NULL)
return NULL;
hr = CoCreateInstance(save ? &CLSID_FileSaveDialog : &CLSID_FileOpenDialog, NULL, CLSCTX_INPROC,
&IID_IFileDialog, (LPVOID)&pfd);
dialog_showing++;
if (FAILED(hr)) {
SetLastError(hr);
uprintf("CoCreateInstance for FileOpenDialog failed: %s\n", WindowsErrorString());
if (pfd != NULL) {
IFileDialog_Release(pfd);
pfd = NULL; // Just in case
}
goto fallback;
}
// Setup the file extension filter table
for (i = 0; i < ext->count; i++) {
filter_spec[i].pszSpec = utf8_to_wchar(ext->extension[i]);
filter_spec[i].pszName = utf8_to_wchar(ext->description[i]);
}
filter_spec[i].pszSpec = L"*.*";
filter_spec[i].pszName = utf8_to_wchar(lmprintf(MSG_107));
// Set the file extension filters
IFileDialog_SetFileTypes(pfd, (UINT)ext->count + 1, filter_spec);
hr = CoCreateInstance(save ? &CLSID_FileSaveDialog : &CLSID_FileOpenDialog, NULL, CLSCTX_INPROC,
&IID_IFileDialog, (LPVOID)&pfd);
if (SUCCEEDED(hr) && (pfd == NULL)) // Never trust Microsoft APIs to do the right thing
hr = ERROR_SEVERITY_ERROR | FAC(FACILITY_WINDOWS) | ERROR_API_UNAVAILABLE;
if (path == NULL) {
// Try to use the "Downloads" folder as the initial default directory
const GUID download_dir_guid =
{ 0x374de290, 0x123f, 0x4565, { 0x91, 0x64, 0x39, 0xc4, 0x92, 0x5e, 0x46, 0x7b } };
hr = SHGetKnownFolderPath(&download_dir_guid, 0, 0, &wpath);
if (SUCCEEDED(hr)) {
hr = SHCreateItemFromParsingName(wpath, NULL, &IID_IShellItem, (LPVOID)&si_path);
if (SUCCEEDED(hr)) {
IFileDialog_SetDefaultFolder(pfd, si_path);
}
CoTaskMemFree(wpath);
}
} else {
wpath = utf8_to_wchar(path);
if (FAILED(hr)) {
SetLastError(hr);
uprintf("CoCreateInstance for FileOpenDialog failed: %s", WindowsErrorString());
goto out;
}
// Set the file extension filters
IFileDialog_SetFileTypes(pfd, (UINT)ext->count + 1, filter_spec);
if (path == NULL) {
// Try to use the "Downloads" folder as the initial default directory
const GUID download_dir_guid =
{ 0x374de290, 0x123f, 0x4565, { 0x91, 0x64, 0x39, 0xc4, 0x92, 0x5e, 0x46, 0x7b } };
hr = SHGetKnownFolderPath(&download_dir_guid, 0, 0, &wpath);
if (SUCCEEDED(hr)) {
hr = SHCreateItemFromParsingName(wpath, NULL, &IID_IShellItem, (LPVOID)&si_path);
if (SUCCEEDED(hr)) {
IFileDialog_SetFolder(pfd, si_path);
IFileDialog_SetDefaultFolder(pfd, si_path);
}
safe_free(wpath);
CoTaskMemFree(wpath);
}
// Set the default filename
wfilename = utf8_to_wchar((ext->filename == NULL) ? "" : ext->filename);
if (wfilename != NULL) {
IFileDialog_SetFileName(pfd, wfilename);
}
// Set a default extension so that when the user switches filters it gets
// automatically updated. Note that the IFileDialog::SetDefaultExtension()
// doc says the extension shouldn't be prefixed with unwanted characters
// but it appears to work regardless so we don't bother cleaning it.
wext = utf8_to_wchar((ext->extension == NULL) ? "" : ext->extension[0]);
if (wext != NULL) {
IFileDialog_SetDefaultExtension(pfd, wext);
}
// Display the dialog
hr = IFileDialog_Show(pfd, hMainDialog);
// Cleanup
safe_free(wext);
safe_free(wfilename);
for (i = 0; i < ext->count; i++) {
safe_free(filter_spec[i].pszSpec);
safe_free(filter_spec[i].pszName);
}
safe_free(filter_spec[i].pszName);
safe_free(filter_spec);
} else {
wpath = utf8_to_wchar(path);
hr = SHCreateItemFromParsingName(wpath, NULL, &IID_IShellItem, (LPVOID)&si_path);
if (SUCCEEDED(hr)) {
// Obtain the result of the user's interaction with the dialog.
hr = IFileDialog_GetResult(pfd, &psiResult);
if (SUCCEEDED(hr)) {
hr = IShellItem_GetDisplayName(psiResult, SIGDN_FILESYSPATH, &wpath);
if (SUCCEEDED(hr)) {
filepath = wchar_to_utf8(wpath);
CoTaskMemFree(wpath);
} else {
SetLastError(hr);
uprintf("Unable to access file path: %s\n", WindowsErrorString());
}
IShellItem_Release(psiResult);
}
} else if ((hr & 0xFFFF) != ERROR_CANCELLED) {
// If it's not a user cancel, assume the dialog didn't show and fallback
SetLastError(hr);
uprintf("Could not show FileOpenDialog: %s\n", WindowsErrorString());
goto fallback;
IFileDialog_SetFolder(pfd, si_path);
}
IFileDialog_Release(pfd);
dialog_showing--;
return filepath;
safe_free(wpath);
}
fallback:
// Set the default filename
wfilename = utf8_to_wchar((ext->filename == NULL) ? "" : ext->filename);
if (wfilename != NULL)
IFileDialog_SetFileName(pfd, wfilename);
// Set a default extension so that when the user switches filters it gets
// automatically updated. Note that the IFileDialog::SetDefaultExtension()
// doc says the extension shouldn't be prefixed with unwanted characters
// but it appears to work regardless so we don't bother cleaning it.
wext = utf8_to_wchar((ext->extension == NULL) ? "" : ext->extension[0]);
if (wext != NULL)
IFileDialog_SetDefaultExtension(pfd, wext);
// Set the current selected extension
IFileDialog_SetFileTypeIndex(pfd, selected_ext == NULL ? 0 : *selected_ext);
// Display the dialog and (optionally) get the selected extension index
hr = IFileDialog_Show(pfd, hMainDialog);
if (selected_ext != NULL)
IFileDialog_GetFileTypeIndex(pfd, selected_ext);
// Cleanup
safe_free(wext);
safe_free(wfilename);
for (i = 0; i < ext->count; i++) {
safe_free(filter_spec[i].pszSpec);
safe_free(filter_spec[i].pszName);
}
safe_free(filter_spec[i].pszName);
safe_free(filter_spec);
if (pfd != NULL) {
IFileDialog_Release(pfd);
if (SUCCEEDED(hr)) {
// Obtain the result of the user's interaction with the dialog.
hr = IFileDialog_GetResult(pfd, &psiResult);
if (SUCCEEDED(hr)) {
hr = IShellItem_GetDisplayName(psiResult, SIGDN_FILESYSPATH, &wpath);
if (SUCCEEDED(hr)) {
filepath = wchar_to_utf8(wpath);
CoTaskMemFree(wpath);
} else {
SetLastError(hr);
uprintf("Unable to access file path: %s", WindowsErrorString());
}
IShellItem_Release(psiResult);
}
} else if (HRESULT_CODE(hr) != ERROR_CANCELLED) {
// If it's not a user cancel, assume the dialog didn't show and fallback
SetLastError(hr);
uprintf("Could not show FileOpenDialog: %s", WindowsErrorString());
}
memset(&ofn, 0, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = hMainDialog;
// Selected File name
static_sprintf(selected_name, "%s", (ext->filename == NULL)?"":ext->filename);
ofn.lpstrFile = selected_name;
ofn.nMaxFile = MAX_PATH;
// Set the file extension filters
all_files = lmprintf(MSG_107);
ext_strlen = 0;
for (i=0; i<ext->count; i++) {
ext_strlen += safe_strlen(ext->description[i]) + 2*safe_strlen(ext->extension[i]) + sizeof(" ()\r\r");
}
ext_strlen += safe_strlen(all_files) + sizeof(" (*.*)\r*.*\r");
ext_string = (char*)malloc(ext_strlen+1);
if (ext_string == NULL)
return NULL;
ext_string[0] = 0;
for (i=0, j=0; i<ext->count; i++) {
j += _snprintf(&ext_string[j], ext_strlen-j, "%s (%s)\r%s\r", ext->description[i], ext->extension[i], ext->extension[i]);
}
j = _snprintf(&ext_string[j], ext_strlen-j, "%s (*.*)\r*.*\r", all_files);
// Microsoft could really have picked a better delimiter!
for (i=0; i<ext_strlen; i++) {
// Since the VS Code Analysis tool is dumb...
#if defined(_MSC_VER)
#pragma warning(suppress: 6385)
#endif
if (ext_string[i] == '\r') {
#if defined(_MSC_VER)
#pragma warning(suppress: 6386)
#endif
ext_string[i] = 0;
}
}
ofn.lpstrFilter = ext_string;
ofn.nFilterIndex = 1;
ofn.lpstrInitialDir = path;
ofn.Flags = OFN_OVERWRITEPROMPT | options;
// Show Dialog
if (save) {
r = GetSaveFileNameU(&ofn);
} else {
r = GetOpenFileNameU(&ofn);
}
if (r) {
filepath = safe_strdup(selected_name);
} else {
tmp = CommDlgExtendedError();
if (tmp != 0) {
uprintf("Could not select file for %s. Error %X\n", save?"save":"open", tmp);
}
}
safe_free(ext_string);
out:
safe_free(filter_spec);
if (pfd != NULL)
IFileDialog_Release(pfd);
dialog_showing--;
return filepath;
}
@ -449,7 +386,7 @@ INT_PTR CALLBACK AboutCallback(HWND hDlg, UINT message, WPARAM wParam, LPARAM lP
ResizeButtonHeight(hDlg, IDOK);
static_sprintf(about_blurb, about_blurb_format, lmprintf(MSG_174|MSG_RTF),
lmprintf(MSG_175|MSG_RTF, rufus_version[0], rufus_version[1], rufus_version[2]),
"Copyright © 2011-2023 Pete Batard",
"Copyright © 2011-2024 Pete Batard",
lmprintf(MSG_176|MSG_RTF), lmprintf(MSG_177|MSG_RTF), lmprintf(MSG_178|MSG_RTF));
for (i = 0; i < ARRAYSIZE(hEdit); i++) {
hEdit[i] = GetDlgItem(hDlg, edit_id[i]);
@ -1700,7 +1637,7 @@ INT_PTR CALLBACK NewVersionCallback(HWND hDlg, UINT message, WPARAM wParam, LPAR
break;
}
dl_ext.filename = PathFindFileNameU(update.download_url);
filepath = FileDialog(TRUE, app_dir, &dl_ext, OFN_NOCHANGEDIR);
filepath = FileDialog(TRUE, app_dir, &dl_ext, NULL);
if (filepath == NULL) {
uprintf("Could not get save path");
break;

View File

@ -2,7 +2,7 @@
*
* Copyright 2003 Lars Munch Christensen - All Rights Reserved
* Copyright 1998-2008 H. Peter Anvin - All Rights Reserved
* Copyright 2012-2021 Pete Batard
* Copyright 2012-2023 Pete Batard
*
* Based on the Linux installer program for SYSLINUX by H. Peter Anvin
*
@ -111,10 +111,10 @@ BOOL InstallSyslinux(DWORD drive_index, char drive_letter, int file_system)
libfat_sector_t *sectors = NULL;
int ldlinux_sectors;
uint32_t ldlinux_cluster;
int i, nsectors, sl_fs_stype;
int i, w, nsectors, sl_fs_stype;
BOOL use_v5 = (boot_type == BT_SYSLINUX_V6) || ((boot_type == BT_IMAGE) && (SL_MAJOR(img_report.sl_version) >= 5));
PrintInfoDebug(0, MSG_234, (boot_type == BT_IMAGE)?img_report.sl_version_str:embedded_sl_version_str[use_v5?1:0]);
PrintInfoDebug(0, MSG_234, (boot_type == BT_IMAGE) ? img_report.sl_version_str : embedded_sl_version_str[use_v5?1:0]);
/* 4K sector size workaround */
SECTOR_SHIFT = 0;
@ -287,8 +287,14 @@ BOOL InstallSyslinux(DWORD drive_index, char drive_letter, int file_system)
goto out;
}
/* Patch ldlinux.sys and the boot sector */
if (syslinux_patch(sectors, nsectors, 0, 0, NULL, NULL) < 0) {
/* Set the base directory and patch ldlinux.sys and the boot sector */
for (i = (int)strlen(img_report.cfg_path); (i > 0) && (img_report.cfg_path[i] != '/'); i--);
if (i > 0)
img_report.cfg_path[i] = 0;
w = syslinux_patch(sectors, nsectors, 0, 0, img_report.cfg_path, NULL);
if (i > 0)
img_report.cfg_path[i] = '/';
if (w < 0) {
uprintf("Could not patch Syslinux files.");
uprintf("WARNING: This could be caused by your firewall having modified downloaded content, such as 'ldlinux.sys'...");
goto out;

View File

@ -40,7 +40,8 @@ int32_t libfat_searchdir(struct libfat_filesystem *fs, int32_t dirclust,
for (nent = 0; nent < LIBFAT_SECTOR_SIZE;
nent += sizeof(struct fat_dirent)) {
if (!memcmp(dep->name, name, 11)) {
/* Filter out volume labels (0x08) and devices (0x40) from the search */
if (!(dep->attribute & 0x48) && !memcmp(dep->name, name, 11)) {
if (direntry) {
memcpy(direntry->entry, dep, sizeof(*dep));
direntry->sector = s;

View File

@ -28,6 +28,7 @@
#include "syslinux.h"
#include "syslxint.h"
extern void uprintf(const char* format, ...);
/*
* Generate sector extents
@ -161,8 +162,8 @@ int syslinux_patch(const sector_t *sectp, int nsectors,
#if 0
if (nsect > nptrs) {
/* Not necessarily an error in this case, but a general problem */
fprintf(stderr, "Insufficient extent space, build error!\n");
exit(1);
uprintf("syslinux_patch: Insufficient extent space, build error!\n");
return -1;
}
#endif
@ -178,8 +179,8 @@ int syslinux_patch(const sector_t *sectp, int nsectors,
if (subdir) {
int sublen = strlen(subdir) + 1;
if (get_16_sl(&epa->dirlen) < sublen) {
fprintf(stderr, "Subdirectory path too long... aborting install!\n");
exit(1);
uprintf("syslinux_patch: Subdirectory path too long... aborting install!");
return -1;
}
memcpy_to_sl(slptr(boot_image, &epa->diroffset), subdir, sublen);
}
@ -188,8 +189,8 @@ int syslinux_patch(const sector_t *sectp, int nsectors,
if (subvol) {
int sublen = strlen(subvol) + 1;
if (get_16_sl(&epa->subvollen) < sublen) {
fprintf(stderr, "Subvol name too long... aborting install!\n");
exit(1);
uprintf("syslinux_patch: Subvol name too long... aborting install!");
return -1;
}
memcpy_to_sl(slptr(boot_image, &epa->subvoloffset), subvol, sublen);
}

View File

@ -126,10 +126,10 @@ static DWORD NtfsSectGetVolumeHandle(
M_ERR("Unable to open volume handle!");
goto err_handle;
}
CloseHandle(VolumeInfo->Handle);
return ERROR_SUCCESS;
CloseHandle(VolumeInfo->Handle);
err_handle:
return rc;

379
src/vhd.c
View File

@ -1,7 +1,7 @@
/*
* Rufus: The Reliable USB Formatting Utility
* Virtual Disk Handling functions
* Copyright © 2013-2023 Pete Batard <pete@akeo.ie>
* Copyright © 2013-2024 Pete Batard <pete@akeo.ie>
*
* 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
@ -29,6 +29,7 @@
#include "vhd.h"
#include "missing.h"
#include "resource.h"
#include "settings.h"
#include "msapi_utf8.h"
#include "drive.h"
@ -58,7 +59,8 @@ typedef struct {
uint32_t wim_nb_files, wim_proc_files, wim_extra_files;
HANDLE wim_thread = NULL;
extern int default_thread_priority;
extern BOOL ignore_boot_marker;
extern char* save_image_type;
extern BOOL ignore_boot_marker, has_ffu_support;
extern RUFUS_DRIVE rufus_drive[MAX_DRIVES];
extern HANDLE format_thread;
@ -67,7 +69,6 @@ static uint32_t progress_report_mask;
static uint64_t progress_offset = 0, progress_total = 100;
static wchar_t wmount_path[MAX_PATH] = { 0 }, wmount_track[MAX_PATH] = { 0 };
static char sevenzip_path[MAX_PATH];
static const char conectix_str[] = VHD_FOOTER_COOKIE;
static BOOL count_files;
static int progress_op = OP_FILE_COPY, progress_msg = MSG_267;
@ -83,7 +84,7 @@ static BOOL Get7ZipPath(void)
typedef struct {
const char* ext;
bled_compression_type type;
uint8_t type;
} comp_assoc;
static comp_assoc file_assoc[] = {
@ -94,38 +95,85 @@ static comp_assoc file_assoc[] = {
{ ".bz2", BLED_COMPRESSION_BZIP2 },
{ ".xz", BLED_COMPRESSION_XZ },
{ ".vtsi", BLED_COMPRESSION_VTSI },
{ ".ffu", BLED_COMPRESSION_MAX },
{ ".vhd", BLED_COMPRESSION_MAX + 1 },
{ ".vhdx", BLED_COMPRESSION_MAX + 2 },
};
// For now we consider that an image that matches a known extension is bootable
static BOOL IsCompressedBootableImage(const char* path)
// Look for a boot marker in the MBR area of the image
static int8_t IsCompressedBootableImage(const char* path)
{
char *p;
char *ext = NULL, *physical_disk = NULL;
unsigned char *buf = NULL;
int i;
BOOL r = FALSE;
int64_t dc;
FILE* fd = NULL;
BOOL r = 0;
int64_t dc = 0;
img_report.compression_type = BLED_COMPRESSION_NONE;
for (p = (char*)&path[strlen(path)-1]; (*p != '.') && (p != path); p--);
if (safe_strlen(path) > 4)
for (ext = (char*)&path[safe_strlen(path) - 1]; (*ext != '.') && (ext != path); ext--);
if (p == path)
return FALSE;
for (i = 0; i<ARRAYSIZE(file_assoc); i++) {
if (strcmp(p, file_assoc[i].ext) == 0) {
for (i = 0; i < ARRAYSIZE(file_assoc); i++) {
if (safe_stricmp(ext, file_assoc[i].ext) == 0) {
img_report.compression_type = file_assoc[i].type;
buf = malloc(MBR_SIZE);
if (buf == NULL)
return FALSE;
return 0;
FormatStatus = 0;
bled_init(0, uprintf, NULL, NULL, NULL, NULL, &FormatStatus);
dc = bled_uncompress_to_buffer(path, (char*)buf, MBR_SIZE, file_assoc[i].type);
bled_exit();
if (img_report.compression_type < BLED_COMPRESSION_MAX) {
bled_init(0, uprintf, NULL, NULL, NULL, NULL, &FormatStatus);
dc = bled_uncompress_to_buffer(path, (char*)buf, MBR_SIZE, file_assoc[i].type);
bled_exit();
} else if (img_report.compression_type == BLED_COMPRESSION_MAX) {
// Dism, through FfuProvider.dll, can mount a .ffu as a physicaldrive, which we
// could then use to poke the MBR as we do for VHD... Except Microsoft did design
// dism to FAIL AND EXIT, after mounting the ffu as a virtual drive, if it doesn't
// find something that looks like Windows at the specified image index... which it
// usually won't in our case. So, curse Microsoft and their incredible short-
// sightedness (or, most likely in this case, intentional malice, by BREACHING the
// OS contract to keep useful disk APIs for their usage, and their usage only).
// Then again, considering that .ffu's are GPT based, the marker should always be
// present, so just check for the FFU signature and pretend there's a marker then.
if (has_ffu_support) {
fd = fopenU(path, "rb");
if (fd != NULL) {
img_report.is_vhd = TRUE;
dc = fread(buf, 1, MBR_SIZE, fd);
fclose(fd);
// The signature may not be constant, but since the only game in town to
// create FFU is dism, and dism appears to use "SignedImage " always,.we
// might as well use this to our advantage.
if (strncmp(&buf[4], "SignedImage ", 12) == 0) {
// At this stage, the buffer is only used for marker validation.
buf[0x1FE] = 0x55;
buf[0x1FF] = 0xAA;
}
} else
uprintf("Could not open %s: %d", path, errno);
} else {
uprintf(" An FFU image was selected, but this system does not have FFU support!");
}
} else {
physical_disk = VhdMountImage(path);
if (physical_disk != NULL) {
img_report.is_vhd = TRUE;
fd = fopenU(physical_disk, "rb");
if (fd != NULL) {
dc = fread(buf, 1, MBR_SIZE, fd);
fclose(fd);
}
}
VhdUnmountImage();
}
if (dc != MBR_SIZE) {
free(buf);
return FALSE;
}
r = (buf[0x1FE] == 0x55) && (buf[0x1FF] == 0xAA);
if ((buf[0x1FE] == 0x55) && (buf[0x1FF] == 0xAA))
r = 1;
else if (ignore_boot_marker)
r = 2;
free(buf);
return r;
}
@ -139,10 +187,7 @@ int8_t IsBootableImage(const char* path)
{
HANDLE handle = INVALID_HANDLE_VALUE;
LARGE_INTEGER liImageSize;
vhd_footer* footer = NULL;
DWORD size;
size_t i;
uint32_t checksum, old_checksum;
uint64_t wim_magic = 0;
LARGE_INTEGER ptr = { 0 };
int8_t is_bootable_img;
@ -171,40 +216,7 @@ int8_t IsBootableImage(const char* path)
if (img_report.is_windows_img)
goto out;
size = sizeof(vhd_footer);
if ((img_report.compression_type == BLED_COMPRESSION_NONE) && (img_report.image_size >= (512 + size))) {
footer = (vhd_footer*)malloc(size);
ptr.QuadPart = img_report.image_size - size;
if ( (footer == NULL) || (!SetFilePointerEx(handle, ptr, NULL, FILE_BEGIN)) ||
(!ReadFile(handle, footer, size, &size, NULL)) || (size != sizeof(vhd_footer)) ) {
uprintf(" Could not read VHD footer");
is_bootable_img = -3;
goto out;
}
if (memcmp(footer->cookie, conectix_str, sizeof(footer->cookie)) == 0) {
img_report.image_size -= sizeof(vhd_footer);
if ( (bswap_uint32(footer->file_format_version) != VHD_FOOTER_FILE_FORMAT_V1_0)
|| (bswap_uint32(footer->disk_type) != VHD_FOOTER_TYPE_FIXED_HARD_DISK)) {
uprintf(" Unsupported type of VHD image");
is_bootable_img = 0;
goto out;
}
// Might as well validate the checksum while we're at it
old_checksum = bswap_uint32(footer->checksum);
footer->checksum = 0;
for (checksum = 0, i = 0; i < sizeof(vhd_footer); i++)
checksum += ((uint8_t*)footer)[i];
checksum = ~checksum;
if (checksum != old_checksum)
uprintf(" Warning: VHD footer seems corrupted (checksum: %04X, expected: %04X)", old_checksum, checksum);
// Need to remove the footer from our payload
uprintf(" Image is a Fixed Hard Disk VHD file");
img_report.is_vhd = TRUE;
}
}
out:
safe_free(footer);
safe_closehandle(handle);
return is_bootable_img;
}
@ -405,7 +417,7 @@ char* WimMountImage(const char* image, int index)
mp.index = index;
// Try to unmount an existing stale image, if there is any
mount_path = GetExistingMountPoint(image, index);
mount_path = WimGetExistingMountPoint(image, index);
if (mount_path != NULL) {
uprintf("WARNING: Found stale '%s [%d]' image mounted on '%s' - Attempting to unmount it...",
image, index, mount_path);
@ -499,7 +511,7 @@ BOOL WimUnmountImage(const char* image, int index, BOOL commit)
// This basically parses HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WIMMount\Mounted Images
// to see if an instance exists with the image/index passed as parameter and returns
// the mount point of this image if found, or NULL otherwise.
char* GetExistingMountPoint(const char* image, int index)
char* WimGetExistingMountPoint(const char* image, int index)
{
static char path[MAX_PATH];
char class[MAX_PATH] = "", guid[40], key_name[MAX_PATH];
@ -885,21 +897,116 @@ BOOL WimApplyImage(const char* image, int index, const char* dst)
return dw;
}
// VirtDisk API Prototypes since we can't use delay-loading because of MinGW
// See https://github.com/pbatard/rufus/issues/2272#issuecomment-1615976013
PF_TYPE_DECL(WINAPI, DWORD, CreateVirtualDisk, (PVIRTUAL_STORAGE_TYPE, PCWSTR,
VIRTUAL_DISK_ACCESS_MASK, PSECURITY_DESCRIPTOR, CREATE_VIRTUAL_DISK_FLAG, ULONG,
PCREATE_VIRTUAL_DISK_PARAMETERS, LPOVERLAPPED, PHANDLE));
PF_TYPE_DECL(WINAPI, DWORD, OpenVirtualDisk, (PVIRTUAL_STORAGE_TYPE, PCWSTR,
VIRTUAL_DISK_ACCESS_MASK, OPEN_VIRTUAL_DISK_FLAG, POPEN_VIRTUAL_DISK_PARAMETERS, PHANDLE));
PF_TYPE_DECL(WINAPI, DWORD, AttachVirtualDisk, (HANDLE, PSECURITY_DESCRIPTOR,
ATTACH_VIRTUAL_DISK_FLAG, ULONG, PATTACH_VIRTUAL_DISK_PARAMETERS, LPOVERLAPPED));
PF_TYPE_DECL(WINAPI, DWORD, DetachVirtualDisk, (HANDLE, DETACH_VIRTUAL_DISK_FLAG, ULONG));
PF_TYPE_DECL(WINAPI, DWORD, GetVirtualDiskPhysicalPath, (HANDLE, PULONG, PWSTR));
PF_TYPE_DECL(WINAPI, DWORD, GetVirtualDiskOperationProgress, (HANDLE, LPOVERLAPPED,
PVIRTUAL_DISK_PROGRESS));
static char physical_path[128] = "";
static HANDLE mounted_handle = INVALID_HANDLE_VALUE;
// Mount an ISO or a VHD/VHDX image
// Returns the physical path of the mounted image or NULL on error.
char* VhdMountImage(const char* path)
{
VIRTUAL_STORAGE_TYPE vtype = { VIRTUAL_STORAGE_TYPE_DEVICE_ISO, VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT };
ATTACH_VIRTUAL_DISK_PARAMETERS vparams = { 0 };
DWORD r;
wchar_t wtmp[128];
ULONG size = ARRAYSIZE(wtmp);
wconvert(path);
char *ret = NULL, *ext = NULL;
PF_INIT_OR_OUT(OpenVirtualDisk, VirtDisk);
PF_INIT_OR_OUT(AttachVirtualDisk, VirtDisk);
PF_INIT_OR_OUT(GetVirtualDiskPhysicalPath, VirtDisk);
if (wpath == NULL)
return NULL;
if ((mounted_handle != NULL) && (mounted_handle != INVALID_HANDLE_VALUE))
VhdUnmountImage();
if (safe_strlen(path) > 4)
for (ext = (char*)&path[safe_strlen(path) - 1]; (*ext != '.') && (ext != path); ext--);
if (safe_stricmp(ext, ".vhdx") == 0)
vtype.DeviceId = VIRTUAL_STORAGE_TYPE_DEVICE_VHDX;
else if (safe_stricmp(ext, ".vhd") == 0)
vtype.DeviceId = VIRTUAL_STORAGE_TYPE_DEVICE_VHD;
r = pfOpenVirtualDisk(&vtype, wpath, VIRTUAL_DISK_ACCESS_READ | VIRTUAL_DISK_ACCESS_GET_INFO,
OPEN_VIRTUAL_DISK_FLAG_NONE, NULL, &mounted_handle);
if (r != ERROR_SUCCESS) {
SetLastError(r);
uprintf("Could not open image '%s': %s", path, WindowsErrorString());
goto out;
}
vparams.Version = ATTACH_VIRTUAL_DISK_VERSION_1;
r = pfAttachVirtualDisk(mounted_handle, NULL, ATTACH_VIRTUAL_DISK_FLAG_READ_ONLY |
ATTACH_VIRTUAL_DISK_FLAG_NO_DRIVE_LETTER, 0, &vparams, NULL);
if (r != ERROR_SUCCESS) {
SetLastError(r);
uprintf("Could not mount image '%s': %s", path, WindowsErrorString());
goto out;
}
r = pfGetVirtualDiskPhysicalPath(mounted_handle, &size, wtmp);
if (r != ERROR_SUCCESS) {
SetLastError(r);
uprintf("Could not obtain physical path for mounted image '%s': %s", path, WindowsErrorString());
goto out;
}
wchar_to_utf8_no_alloc(wtmp, physical_path, sizeof(physical_path));
ret = physical_path;
out:
if (ret == NULL)
VhdUnmountImage();
wfree(path);
return ret;
}
void VhdUnmountImage(void)
{
PF_INIT_OR_OUT(DetachVirtualDisk, VirtDisk);
if ((mounted_handle == NULL) || (mounted_handle == INVALID_HANDLE_VALUE))
goto out;
pfDetachVirtualDisk(mounted_handle, DETACH_VIRTUAL_DISK_FLAG_NONE, 0);
safe_closehandle(mounted_handle);
out:
physical_path[0] = 0;
}
// Since we no longer have to deal with Windows 7, we can call on CreateVirtualDisk()
// to backup a physical disk to VHD/VHDX. Now if this could also be used to create an
// ISO from optical media that would be swell, but no matter what I tried, it didn't
// seem possible...
static DWORD WINAPI SaveImageThread(void* param)
static DWORD WINAPI VhdSaveImageThread(void* param)
{
IMG_SAVE* img_save = (IMG_SAVE*)param;
HANDLE handle = INVALID_HANDLE_VALUE;
WCHAR* wSrc = utf8_to_wchar(img_save->DevicePath);
WCHAR* wDst = utf8_to_wchar(img_save->ImagePath);
WCHAR* wSrc = utf8_to_wchar(GetPhysicalName(img_save->DeviceNum));
VIRTUAL_STORAGE_TYPE vtype = { img_save->Type, VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT };
STOPGAP_CREATE_VIRTUAL_DISK_PARAMETERS vparams = { 0 };
VIRTUAL_DISK_PROGRESS vprogress = { 0 };
OVERLAPPED overlapped = { 0 };
DWORD result, flags;
DWORD r = ERROR_NOT_FOUND, flags;
PF_INIT_OR_OUT(CreateVirtualDisk, VirtDisk);
PF_INIT_OR_OUT(GetVirtualDiskOperationProgress, VirtDisk);
assert(img_save->Type == VIRTUAL_STORAGE_TYPE_DEVICE_VHD ||
img_save->Type == VIRTUAL_STORAGE_TYPE_DEVICE_VHDX);
@ -919,7 +1026,7 @@ static DWORD WINAPI SaveImageThread(void* param)
flags = CREATE_VIRTUAL_DISK_FLAG_CREATE_BACKING_STORAGE;
// The following ensures that VHD images are stored uncompressed and can
// be used as DD images.
if (img_save->Type != VIRTUAL_STORAGE_TYPE_DEVICE_VHDX)
if (img_save->Type == VIRTUAL_STORAGE_TYPE_DEVICE_VHD)
flags |= CREATE_VIRTUAL_DISK_FLAG_FULL_PHYSICAL_ALLOCATION;
// TODO: Use CREATE_VIRTUAL_DISK_FLAG_PREVENT_WRITES_TO_SOURCE_DISK?
@ -928,97 +1035,157 @@ static DWORD WINAPI SaveImageThread(void* param)
// CreateVirtualDisk() does not have an overwrite flag...
DeleteFileW(wDst);
result = CreateVirtualDisk(&vtype, wDst, VIRTUAL_DISK_ACCESS_NONE, NULL,
r = pfCreateVirtualDisk(&vtype, wDst, VIRTUAL_DISK_ACCESS_NONE, NULL,
flags, 0, (PCREATE_VIRTUAL_DISK_PARAMETERS)&vparams, &overlapped, &handle);
if (result != ERROR_SUCCESS && result != ERROR_IO_PENDING) {
SetLastError(result);
if (r != ERROR_SUCCESS && r != ERROR_IO_PENDING) {
SetLastError(r);
uprintf("Could not create virtual disk: %s", WindowsErrorString());
goto out;
}
if (result == ERROR_IO_PENDING) {
while ((result = WaitForSingleObject(overlapped.hEvent, 100)) == WAIT_TIMEOUT) {
if (r == ERROR_IO_PENDING) {
while ((r = WaitForSingleObject(overlapped.hEvent, 100)) == WAIT_TIMEOUT) {
if (IS_ERROR(FormatStatus) && (SCODE_CODE(FormatStatus) == ERROR_CANCELLED)) {
CancelIoEx(handle, &overlapped);
goto out;
}
if (GetVirtualDiskOperationProgress(handle, &overlapped, &vprogress) == ERROR_SUCCESS) {
if (pfGetVirtualDiskOperationProgress(handle, &overlapped, &vprogress) == ERROR_SUCCESS) {
if (vprogress.OperationStatus == ERROR_IO_PENDING)
UpdateProgressWithInfo(OP_FORMAT, MSG_261, vprogress.CurrentValue, vprogress.CompletionValue);
}
}
if (result != WAIT_OBJECT_0) {
if (r != WAIT_OBJECT_0) {
uprintf("Could not save virtual disk: %s", WindowsErrorString());
goto out;
}
}
r = 0;
UpdateProgressWithInfo(OP_FORMAT, MSG_261, SelectedDrive.DiskSize, SelectedDrive.DiskSize);
uprintf("Operation complete.");
out:
safe_closehandle(handle);
safe_closehandle(overlapped.hEvent);
safe_free(wDst);
safe_closehandle(handle);
safe_free(wSrc);
safe_free(wDst);
safe_free(img_save->DevicePath);
safe_free(img_save->ImagePath);
PostMessage(hMainDialog, UM_FORMAT_COMPLETED, (WPARAM)TRUE, 0);
ExitThread(0);
ExitThread(r);
}
void SaveVHD(void)
// FfuProvider.dll has some nice FfuApplyImage()/FfuCaptureImage() calls... which
// Microsoft decided not make public!
// Considering that trying to both figure out how to use these internal function
// calls, as well as how to properly hook into the DLL for every arch/every release
// of Windows, would be a massive timesink, we just take a shortcut by calling dism
// directly, as imperfect as such a solution might be...
static DWORD WINAPI FfuSaveImageThread(void* param)
{
static IMG_SAVE img_save = { 0 };
DWORD r;
IMG_SAVE* img_save = (IMG_SAVE*)param;
char cmd[MAX_PATH + 128], letters[27], *label;
GetDriveLabel(SelectedDrive.DeviceNumber, letters, &label, TRUE);
static_sprintf(cmd, "dism /Capture-Ffu /CaptureDrive:%s /ImageFile:\"%s\" "
"/Name:\"%s\" /Description:\"Created by %s (%s)\"",
img_save->DevicePath, img_save->ImagePath, label, APPLICATION_NAME, RUFUS_URL);
uprintf("Running command: '%s", cmd);
r = RunCommandWithProgress(cmd, sysnative_dir, TRUE, MSG_261);
if (r != 0 && !IS_ERROR(FormatStatus)) {
SetLastError(r);
uprintf("Failed to capture FFU image: %s", WindowsErrorString());
FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_WINDOWS) | SCODE_CODE(r);
}
safe_free(img_save->DevicePath);
safe_free(img_save->ImagePath);
PostMessage(hMainDialog, UM_FORMAT_COMPLETED, (WPARAM)TRUE, 0);
ExitThread(r);
}
void VhdSaveImage(void)
{
UINT i;
static IMG_SAVE img_save;
char filename[128];
char path[MAX_PATH];
int DriveIndex = ComboBox_GetCurSel(hDeviceList);
EXT_DECL(img_ext, filename, __VA_GROUP__("*.vhdx", "*.vhd"), __VA_GROUP__(lmprintf(MSG_342), lmprintf(MSG_343)));
enum { image_type_vhd = 1, image_type_vhdx = 2, image_type_ffu = 3 };
static EXT_DECL(img_ext, filename, __VA_GROUP__("*.vhd", "*.vhdx", "*.ffu"),
__VA_GROUP__(lmprintf(MSG_343), lmprintf(MSG_342), lmprintf(MSG_344)));
ULARGE_INTEGER free_space;
memset(&img_save, 0, sizeof(IMG_SAVE));
if ((DriveIndex < 0) || (format_thread != NULL))
return;
static_sprintf(filename, "%s.vhdx", rufus_drive[DriveIndex].label);
static_sprintf(filename, "%s", rufus_drive[DriveIndex].label);
img_save.DeviceNum = (DWORD)ComboBox_GetItemData(hDeviceList, DriveIndex);
img_save.ImagePath = FileDialog(TRUE, NULL, &img_ext, 0);
img_save.Type = safe_strstr(img_save.ImagePath, ".vhdx") != NULL ?
VIRTUAL_STORAGE_TYPE_DEVICE_VHDX : VIRTUAL_STORAGE_TYPE_DEVICE_VHD;
img_save.DevicePath = GetPhysicalName(img_save.DeviceNum);
// FFU support requires GPT
img_ext.count = (!has_ffu_support || SelectedDrive.PartitionStyle != PARTITION_STYLE_GPT) ? 2 : 3;
for (i = 1; i <= (UINT)img_ext.count && (safe_strcmp(save_image_type , &_img_ext_x[i - 1][2]) != 0); i++);
if (i > (UINT)img_ext.count)
i = image_type_vhdx;
img_save.ImagePath = FileDialog(TRUE, NULL, &img_ext, &i);
if (img_save.ImagePath == NULL)
goto out;
for (i = 1; i <= (UINT)img_ext.count && (strstr(img_save.ImagePath, &_img_ext_x[i - 1][1]) == NULL); i++);
if (i > (UINT)img_ext.count) {
uprintf("Warning: Can not determine image type from extension - Saving to uncompressed VHD.");
i = image_type_vhd;
} else {
save_image_type = (char*)&_img_ext_x[i - 1][2];
WriteSettingStr(SETTING_PREFERRED_SAVE_IMAGE_TYPE, save_image_type);
}
switch (i) {
case image_type_vhd:
img_save.Type = VIRTUAL_STORAGE_TYPE_DEVICE_VHD;
break;
case image_type_ffu:
img_save.Type = VIRTUAL_STORAGE_TYPE_DEVICE_FFU;
break;
default:
img_save.Type = VIRTUAL_STORAGE_TYPE_DEVICE_VHDX;
break;
}
img_save.BufSize = DD_BUFFER_SIZE;
img_save.DeviceSize = SelectedDrive.DiskSize;
if (img_save.ImagePath != NULL) {
if (img_save.DevicePath != NULL && img_save.ImagePath != NULL) {
// Reset all progress bars
SendMessage(hMainDialog, UM_PROGRESS_INIT, 0, 0);
FormatStatus = 0;
free_space.QuadPart = 0;
if ((GetVolumePathNameA(img_save.ImagePath, path, sizeof(path)))
&& (GetDiskFreeSpaceExA(path, &free_space, NULL, NULL))
&& ((LONGLONG)free_space.QuadPart > (SelectedDrive.DiskSize + 512))) {
// Disable all controls except cancel
EnableControls(FALSE, FALSE);
FormatStatus = 0;
InitProgress(TRUE);
format_thread = CreateThread(NULL, 0, SaveImageThread, &img_save, 0, NULL);
if (format_thread != NULL) {
uprintf("\r\nSave to VHD operation started");
PrintInfo(0, -1);
SendMessage(hMainDialog, UM_TIMER_START, 0, 0);
} else {
uprintf("Unable to start VHD save thread");
FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | APPERR(ERROR_CANT_START_THREAD);
safe_free(img_save.ImagePath);
PostMessage(hMainDialog, UM_FORMAT_COMPLETED, (WPARAM)FALSE, 0);
}
} else {
if (free_space.QuadPart == 0) {
uprintf("Unable to isolate drive name for VHD save");
FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | ERROR_PATH_NOT_FOUND;
} else {
// TODO: Might be salvageable for compressed VHDX
if (img_save.Type == VIRTUAL_STORAGE_TYPE_DEVICE_VHD) {
free_space.QuadPart = 0;
if ((GetVolumePathNameA(img_save.ImagePath, path, sizeof(path)))
&& (GetDiskFreeSpaceExA(path, &free_space, NULL, NULL))
&& ((LONGLONG)free_space.QuadPart < (SelectedDrive.DiskSize + 512))) {
uprintf("The VHD size is too large for the target drive");
FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | ERROR_FILE_TOO_LARGE;
PostMessage(hMainDialog, UM_FORMAT_COMPLETED, (WPARAM)FALSE, 0);
goto out;
}
safe_free(img_save.ImagePath);
}
// Disable all controls except Cancel
EnableControls(FALSE, FALSE);
FormatStatus = 0;
InitProgress(TRUE);
format_thread = CreateThread(NULL, 0, img_save.Type == VIRTUAL_STORAGE_TYPE_DEVICE_FFU ?
FfuSaveImageThread : VhdSaveImageThread, &img_save, 0, NULL);
if (format_thread != NULL) {
uprintf("\r\nSave to VHD operation started");
PrintInfo(0, -1);
SendMessage(hMainDialog, UM_TIMER_START, 0, 0);
} else {
uprintf("Unable to start VHD save thread");
FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | APPERR(ERROR_CANT_START_THREAD);
PostMessage(hMainDialog, UM_FORMAT_COMPLETED, (WPARAM)FALSE, 0);
}
}
out:
if (format_thread == NULL) {
safe_free(img_save.DevicePath);
safe_free(img_save.ImagePath);
}
}

View File

@ -23,23 +23,6 @@
#pragma once
#define VHD_FOOTER_COOKIE { 'c', 'o', 'n', 'e', 'c', 't', 'i', 'x' }
#define VHD_FOOTER_FEATURES_NONE 0x00000000
#define VHD_FOOTER_FEATURES_TEMPORARY 0x00000001
#define VHD_FOOTER_FEATURES_RESERVED 0x00000002
#define VHD_FOOTER_FILE_FORMAT_V1_0 0x00010000
#define VHD_FOOTER_DATA_OFFSET_FIXED_DISK 0xFFFFFFFFFFFFFFFFULL
#define VHD_FOOTER_CREATOR_HOST_OS_WINDOWS { 'W', 'i', '2', 'k' }
#define VHD_FOOTER_CREATOR_HOST_OS_MAC { 'M', 'a', 'c', ' ' }
#define VHD_FOOTER_TYPE_FIXED_HARD_DISK 0x00000002
#define VHD_FOOTER_TYPE_DYNAMIC_HARD_DISK 0x00000003
#define VHD_FOOTER_TYPE_DIFFER_HARD_DISK 0x00000004
#define WIM_MAGIC 0x0000004D4957534DULL // "MSWIM\0\0\0"
#define WIM_HAS_API_EXTRACT 1
#define WIM_HAS_7Z_EXTRACT 2
@ -72,7 +55,10 @@
#define MBR_SIZE 512 // Might need to review this once we see bootable 4k systems
// TODO: Remove this once MinGW has been updated
#ifndef VIRTUAL_STORAGE_TYPE_DEVICE_VHDX
#define VIRTUAL_STORAGE_TYPE_DEVICE_VHDX 3
#endif
#define VIRTUAL_STORAGE_TYPE_DEVICE_FFU 99
#define CREATE_VIRTUAL_DISK_VERSION_2 2
#define CREATE_VIRTUAL_DISK_FLAG_CREATE_BACKING_STORAGE 8
@ -139,40 +125,6 @@ enum WIMMessage {
WIM_MSG_ABORT_IMAGE = -1
};
/*
* VHD Fixed HD footer (Big Endian)
* http://download.microsoft.com/download/f/f/e/ffef50a5-07dd-4cf8-aaa3-442c0673a029/Virtual%20Hard%20Disk%20Format%20Spec_10_18_06.doc
* NB: If a dymamic implementation is needed, check the GPL v3 compatible C++ implementation from:
* https://sourceforge.net/p/urbackup/backend/ci/master/tree/fsimageplugin/
*/
#pragma pack(push, 1)
typedef struct vhd_footer {
char cookie[8];
uint32_t features;
uint32_t file_format_version;
uint64_t data_offset;
uint32_t timestamp;
char creator_app[4];
uint32_t creator_version;
char creator_host_os[4];
uint64_t original_size;
uint64_t current_size;
union {
uint32_t geometry;
struct {
uint16_t cylinders;
uint8_t heads;
uint8_t sectors;
} chs;
} disk_geometry;
uint32_t disk_type;
uint32_t checksum;
uuid_t unique_id;
uint8_t saved_state;
uint8_t reserved[427];
} vhd_footer;
#pragma pack(pop)
extern uint8_t WimExtractCheck(BOOL bSilent);
extern BOOL WimExtractFile(const char* wim_image, int index, const char* src, const char* dst, BOOL bSilent);
extern BOOL WimExtractFile_API(const char* image, int index, const char* src, const char* dst, BOOL bSilent);
@ -180,8 +132,10 @@ extern BOOL WimExtractFile_7z(const char* image, int index, const char* src, con
extern BOOL WimApplyImage(const char* image, int index, const char* dst);
extern char* WimMountImage(const char* image, int index);
extern BOOL WimUnmountImage(const char* image, int index, BOOL commit);
extern char* GetExistingMountPoint(const char* image, int index);
extern char* WimGetExistingMountPoint(const char* image, int index);
extern BOOL WimIsValidIndex(const char* image, int index);
extern int8_t IsBootableImage(const char* path);
extern void SaveVHD(void);
extern void SaveISO(void);
extern char* VhdMountImage(const char* path);
extern void VhdUnmountImage(void);
extern void VhdSaveImage(void);
extern void IsoSaveImage(void);

View File

@ -1,7 +1,7 @@
/*
* Rufus: The Reliable USB Formatting Utility
* Windows User Experience
* Copyright © 2022-2023 Pete Batard <pete@akeo.ie>
* Copyright © 2022-2024 Pete Batard <pete@akeo.ie>
*
* 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
@ -44,6 +44,7 @@ const char* bypass_name[] = { "BypassTPMCheck", "BypassSecureBootCheck", "Bypass
int unattend_xml_flags = 0, wintogo_index = -1, wininst_index = 0;
int unattend_xml_mask = UNATTEND_DEFAULT_SELECTION_MASK;
char *unattend_xml_path = NULL, unattend_username[MAX_USERNAME_LENGTH];
BOOL is_bootloader_revoked = FALSE;
extern uint32_t wim_nb_files, wim_proc_files, wim_extra_files;
@ -116,6 +117,7 @@ char* CreateUnattendXml(int arch, int flags)
"publicKeyToken=\"31bf3856ad364e35\" versionScope=\"nonSxS\">\n", xml_arch_names[arch]);
fprintf(fd, " <RunSynchronous>\n");
// This part was picked from https://github.com/AveYo/MediaCreationTool.bat/blob/main/bypass11/AutoUnattend.xml
// NB: This is INCOMPATIBLE with S-Mode below
if (flags & UNATTEND_NO_ONLINE_ACCOUNT) {
uprintf("• Bypass online account requirement");
fprintf(fd, " <RunSynchronousCommand wcm:action=\"add\">\n");
@ -225,6 +227,14 @@ char* CreateUnattendXml(int arch, int flags)
fprintf(fd, " <SanPolicy>4</SanPolicy>\n");
fprintf(fd, " </component>\n");
}
if (flags & UNATTEND_FORCE_S_MODE) {
uprintf("• Enforce S Mode");
fprintf(fd, " <component name=\"Microsoft-Windows-CodeIntegrity\" processorArchitecture=\"%s\" language=\"neutral\" "
"xmlns:wcm=\"http://schemas.microsoft.com/WMIConfig/2002/State\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
"publicKeyToken=\"31bf3856ad364e35\" versionScope=\"nonSxS\">\n", xml_arch_names[arch]);
fprintf(fd, " <SkuPolicyRequired>1</SkuPolicyRequired>\n");
fprintf(fd, " </component>\n");
}
fprintf(fd, " </settings>\n");
}
@ -440,7 +450,7 @@ BOOL PopulateWindowsVersion(void)
// If we're not using a straight install.wim, we need to mount the ISO to access it
if (!img_report.is_windows_img) {
mounted_iso = MountISO(image_path);
mounted_iso = VhdMountImage(image_path);
if (mounted_iso == NULL) {
uprintf("Could not mount Windows ISO for build number detection");
return FALSE;
@ -468,7 +478,7 @@ BOOL PopulateWindowsVersion(void)
out:
DeleteFileU(xml_file);
if (!img_report.is_windows_img)
UnMountISO();
VhdUnmountImage();
return ((img_report.win_version.major != 0) && (img_report.win_version.build != 0));
}
@ -481,7 +491,9 @@ BOOL CopySKUSiPolicy(const char* drive_name)
char src[MAX_PATH], dst[MAX_PATH];
struct __stat64 stat64 = { 0 };
if ((target_type != TT_UEFI) || !IS_WINDOWS_1X(img_report) || pe256ssp_size == 0)
// Only copy SkuPolicy if we warned about the bootloader being revoked.
if ((target_type != TT_UEFI) || !IS_WINDOWS_1X(img_report) ||
(pe256ssp_size == 0) || !is_bootloader_revoked)
return r;
static_sprintf(src, "%s\\SecureBootUpdates\\SKUSiPolicy.p7b", system_dir);
@ -532,7 +544,7 @@ int SetWinToGoIndex(void)
// If we're not using a straight install.wim, we need to mount the ISO to access it
if (!img_report.is_windows_img) {
mounted_iso = MountISO(image_path);
mounted_iso = VhdMountImage(image_path);
if (mounted_iso == NULL) {
uprintf("Could not mount ISO for Windows To Go selection");
return -1;
@ -613,7 +625,7 @@ int SetWinToGoIndex(void)
out:
DeleteFileU(xml_file);
if (!img_report.is_windows_img)
UnMountISO();
VhdUnmountImage();
return wintogo_index;
}
@ -640,7 +652,7 @@ BOOL SetupWinToGo(DWORD DriveIndex, const char* drive_name, BOOL use_esp)
}
if (!img_report.is_windows_img) {
mounted_iso = MountISO(image_path);
mounted_iso = VhdMountImage(image_path);
if (mounted_iso == NULL) {
uprintf("Could not mount ISO for Windows To Go installation");
FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | APPERR(ERROR_ISO_EXTRACT);
@ -656,11 +668,11 @@ BOOL SetupWinToGo(DWORD DriveIndex, const char* drive_name, BOOL use_esp)
if (!IS_ERROR(FormatStatus))
FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | APPERR(ERROR_ISO_EXTRACT);
if (!img_report.is_windows_img)
UnMountISO();
VhdUnmountImage();
return FALSE;
}
if (!img_report.is_windows_img)
UnMountISO();
VhdUnmountImage();
if (use_esp) {
uprintf("Setting up EFI System Partition");
@ -678,14 +690,14 @@ BOOL SetupWinToGo(DWORD DriveIndex, const char* drive_name, BOOL use_esp)
// VDS cannot list ESP volumes (talk about allegedly improving on the old disk and volume APIs, only to
// completely neuter it) and IVdsDiskPartitionMF::FormatPartitionEx(), which is what you are supposed to
// use for ESPs, explicitly states: "This method cannot be used to format removable media."
if (!FormatPartition(DriveIndex, partition_offset[PI_ESP], cluster_size, FS_FAT32, "",
if (!FormatPartition(DriveIndex, SelectedDrive.Partition[partition_index[PI_ESP]].Offset, cluster_size, FS_FAT32, "",
FP_QUICK | FP_FORCE | FP_LARGE_FAT32 | FP_NO_BOOT)) {
uprintf("Could not format EFI System Partition");
return FALSE;
}
Sleep(200);
// Need to have the ESP mounted to invoke bcdboot
ms_efi = AltMountVolume(DriveIndex, partition_offset[PI_ESP], FALSE);
ms_efi = AltMountVolume(DriveIndex, SelectedDrive.Partition[partition_index[PI_ESP]].Offset, FALSE);
if (ms_efi == NULL) {
FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | APPERR(ERROR_CANT_ASSIGN_LETTER);
return FALSE;