fix: Simplify error propagation boundaries (#2104)

This commit is contained in:
Kroese
2026-08-07 19:52:06 +02:00
committed by GitHub
parent ff8c17ad04
commit be96767802
3 changed files with 176 additions and 231 deletions
+39 -56
View File
@@ -369,7 +369,7 @@ detectVersion() {
local -a selection_order=() local -a selection_order=()
local result="" index="" local result="" index=""
getVersions "$xml" versions bases groups image_indexes || return 1 getVersions "$xml" versions bases groups image_indexes || return
if [ "${#versions[@]}" -eq 0 ]; then if [ "${#versions[@]}" -eq 0 ]; then
printf '%s\n%s\n' "$result" "$index" printf '%s\n%s\n' "$result" "$index"
@@ -924,7 +924,6 @@ detectReactOS() {
findIsoImage() { findIsoImage() {
local iso="$1" local iso="$1"
local path local path
# Prefer install.wim when both payload forms are present. # Prefer install.wim when both payload forms are present.
@@ -1060,15 +1059,7 @@ readIsoImageInfo() {
result=$(udfread range --ignore-case "$iso" "$image" "$xml_offset" "$xml_size" \ result=$(udfread range --ignore-case "$iso" "$image" "$xml_offset" "$xml_size" \
2>/dev/null | iconv -f UTF-16LE -t UTF-8 2>/dev/null 2>/dev/null | iconv -f UTF-16LE -t UTF-8 2>/dev/null
) || { ) || return
local rc=$?
if (( rc >= 129 )); then
exit "$rc"
fi
return 1
}
[ -n "$result" ] || return 1 [ -n "$result" ] || return 1
@@ -1209,15 +1200,9 @@ readImageInfo() {
local wim="$1" local wim="$1"
local result="" local result=""
result=$(wimlib-imagex info --xml "$wim" | iconv -f UTF-16LE -t UTF-8) || { if ! result=$(wimlib-imagex info --xml "$wim" | iconv -f UTF-16LE -t UTF-8); then
local rc=$?
if (( rc >= 129 )); then
exit "$rc"
fi
result="" result=""
} fi
if [ -z "$result" ]; then if [ -z "$result" ]; then
error "Failed to read Windows image information!" error "Failed to read Windows image information!"
@@ -1349,10 +1334,10 @@ detectImageInfo() {
checkPlatform "$image_info" || exit 67 checkPlatform "$image_info" || exit 67
suggested=$(getSuggestion) || return 1 suggested=$(getSuggestion) || return
local output local output
output=$(detectVersion "$image_info" "$suggested") || return 1 output=$(detectVersion "$image_info" "$suggested") || return
local -a detected=() local -a detected=()
mapfile -t detected <<< "$output" mapfile -t detected <<< "$output"
@@ -1360,19 +1345,19 @@ detectImageInfo() {
DETECTED="${detected[0]:-}" DETECTED="${detected[0]:-}"
index="${detected[1]:-}" index="${detected[1]:-}"
validateEdition || return 1 validateEdition || return
if [ -z "$DETECTED" ]; then if [ -z "$DETECTED" ]; then
unknownImage || return 1 unknownImage || return
return 0 return 0
fi fi
detectLanguage "$image_info" "$index" || return 1 detectLanguage "$image_info" "$index" || return
desc=$(describeImage) || return 1 desc=$(describeImage) || return
info "Detected: $desc" info "Detected: $desc"
configureImage "$index" "$desc" || return 1 configureImage "$index" "$desc" || return
return 0 return 0
} }
@@ -1381,18 +1366,14 @@ detectIsoImage() {
local iso="$1" local iso="$1"
local image header image_info rc local image header image_info
# Return 1 only when no directly inspectable WIM/ESD payload is available so # Return 1 only when no directly inspectable WIM/ESD payload is available so
# the caller may extract the media. Metadata parsing/configuration errors use 2. # the caller may extract the media. Metadata parsing/configuration errors use 2.
image=$(findIsoImage "$iso") || return 1 image=$(findIsoImage "$iso") || return 1
header=$(readWimHeader "$iso" "$image") || return 2 header=$(readWimHeader "$iso" "$image") || return 2
image_info=$(readIsoImageInfo "$iso" "$image" "$header") || { image_info=$(readIsoImageInfo "$iso" "$image" "$header") || return 2
rc=$?
(( rc >= 129 )) && return "$rc"
return 2
}
info "Detecting version from ISO image..." info "Detecting version from ISO image..."
detectImageInfo "$image_info" || return 2 detectImageInfo "$image_info" || return 2
@@ -1471,11 +1452,12 @@ extractESD() {
return 1 return 1
fi fi
if ! xml=$(wimlib-imagex info "$iso" --xml 2>/dev/null | xml=$(wimlib-imagex info "$iso" --xml 2>/dev/null |
iconv -f UTF-16LE -t UTF-8 2>/dev/null); then iconv -f UTF-16LE -t UTF-8 2>/dev/null) || {
ret=$?
error "Cannot read ESD file information!" error "Cannot read ESD file information!"
return 1 return "$ret"
fi }
# Microsoft download ESDs use images 1-3 for setup media, WinPE, and Windows # Microsoft download ESDs use images 1-3 for setup media, WinPE, and Windows
# Setup; images 4 and higher contain installable editions. Read all metadata # Setup; images 4 and higher contain installable editions. Read all metadata
@@ -1531,7 +1513,7 @@ extractESD() {
# installation media. Peak additional usage consists of the extracted setup # installation media. Peak additional usage consists of the extracted setup
# files and boot.wim, plus the final ISO containing those files and the ESD. # files and boot.wim, plus the final ISO containing those files and the ESD.
local freeSpace=$(( size + 2 * (bootSize + wimSize) + spacePad )) local freeSpace=$(( size + 2 * (bootSize + wimSize) + spacePad ))
checkFreeSpace "$dir" "$freeSpace" || return 1 checkFreeSpace "$dir" "$freeSpace" || return
/run/progress.sh "$dir" "$bootSize" "$msg ([P])..." & /run/progress.sh "$dir" "$bootSize" "$msg ([P])..." &
@@ -1540,7 +1522,7 @@ extractESD() {
ret=$? ret=$?
fKill "progress.sh" fKill "progress.sh"
error "Extracting $desc bootdisk failed ($ret)" error "Extracting $desc bootdisk failed ($ret)"
return 1 return "$ret"
} }
fKill "progress.sh" fKill "progress.sh"
@@ -1559,7 +1541,7 @@ extractESD() {
ret=$? ret=$?
fKill "progress.sh" fKill "progress.sh"
error "Adding WinPE failed ($ret)" error "Adding WinPE failed ($ret)"
return 1 return "$ret"
} }
fKill "progress.sh" fKill "progress.sh"
@@ -1575,7 +1557,7 @@ extractESD() {
ret=$? ret=$?
fKill "progress.sh" fKill "progress.sh"
error "Adding Windows Setup failed ($ret)" error "Adding Windows Setup failed ($ret)"
return 1 return "$ret"
} }
fKill "progress.sh" fKill "progress.sh"
@@ -1602,9 +1584,9 @@ extractESD() {
return 1 return 1
fi fi
checkPlatform "$xml" || return 1 checkPlatform "$xml" || return
output=$(detectVersion "$installXml") || return 1 output=$(detectVersion "$installXml") || return
mapfile -t detected <<< "$output" mapfile -t detected <<< "$output"
index="${detected[1]:-}" index="${detected[1]:-}"
@@ -1665,20 +1647,22 @@ extractESD() {
(( image == index )) && continue (( image == index )) && continue
if ! wimlib-imagex delete "$installWim" "$image" --soft --quiet; then wimlib-imagex delete "$installWim" "$image" --soft --quiet || {
ret=$?
fKill "progress.sh" fKill "progress.sh"
error "Failed to remove image $image from install.esd!" error "Failed to remove image $image from install.esd!"
return 1 return "$ret"
fi }
done done
if ! result=$(wimlib-imagex info "$installWim" --xml 2>/dev/null | result=$(wimlib-imagex info "$installWim" --xml 2>/dev/null |
iconv -f UTF-16LE -t UTF-8 2>/dev/null); then iconv -f UTF-16LE -t UTF-8 2>/dev/null) || {
ret=$?
fKill "progress.sh" fKill "progress.sh"
error "Cannot verify the prepared install.esd file!" error "Cannot verify the prepared install.esd file!"
return 1 return "$ret"
fi }
if ! metadata=$(xmlstarlet sel -t \ if ! metadata=$(xmlstarlet sel -t \
-v 'count(/WIM/IMAGE)' -n \ -v 'count(/WIM/IMAGE)' -n \
@@ -2009,7 +1993,7 @@ buildImage() {
local cat="BOOT.CAT" local cat="BOOT.CAT"
local log="/run/shm/iso.log" local log="/run/shm/iso.log"
local base size desc failed="" local base size desc rc=0
if [ -f "$BOOT" ]; then if [ -f "$BOOT" ]; then
error "File $BOOT does already exist?!" && return 1 error "File $BOOT does already exist?!" && return 1
@@ -2118,15 +2102,14 @@ buildImage() {
fi fi
if ! genisoimage "${args[@]}" -quiet "$dir" 2> "$log"; then genisoimage "${args[@]}" -quiet "$dir" 2> "$log" || rc=$?
failed="y"
fi
fKill "progress.sh" fKill "progress.sh"
if [ -n "$failed" ]; then if (( rc != 0 )); then
[ -s "$log" ] && echo "$(<"$log")" [ -s "$log" ] && echo "$(<"$log")"
error "Failed to build image!" && return 1 error "Failed to build image!"
return "$rc"
fi fi
local err="" local err=""
@@ -2139,7 +2122,7 @@ buildImage() {
echo "$err" echo "$err"
fi fi
mv -f "$out" "$BOOT" || return 1 mv -f "$out" "$BOOT" || return
if ! setOwner "$BOOT"; then if ! setOwner "$BOOT"; then
warn "Failed to set the owner for \"$BOOT\" !" warn "Failed to set the owner for \"$BOOT\" !"
+27 -59
View File
@@ -43,8 +43,6 @@ selectWindowsImage() {
local dir="$2" local dir="$2"
local boot="$3" local boot="$3"
local detect_rc=0
# Known versions already provide the required image metadata. # Known versions already provide the required image metadata.
if resolveImage "$VERSION"; then if resolveImage "$VERSION"; then
@@ -67,20 +65,10 @@ selectWindowsImage() {
fi fi
# Inspect unknown media directly before falling back to extraction. # Inspect unknown media directly before falling back to extraction.
detectIsoImage "$iso" || detect_rc=$? detectIsoImage "$iso" && return 0
if (( detect_rc == 0 )); then local rc=$?
return 0 (( rc == 1 )) || return 76
fi
if (( detect_rc >= 129 )); then
return "$detect_rc"
fi
# Only code 1 indicates that extraction may recover detection.
if (( detect_rc != 1 )); then
return 76
fi
if ! extractImage "$iso" "$dir" "$VERSION"; then if ! extractImage "$iso" "$dir" "$VERSION"; then
removeImage "$iso" || : removeImage "$iso" || :
@@ -88,21 +76,11 @@ selectWindowsImage() {
fi fi
extracted=1 extracted=1
detect_rc=0
detectImage "$dir" || detect_rc=$? detectImage "$dir" && return 0
if (( detect_rc == 0 )); then rc=$?
return 0 (( rc == 1 )) || return 76
fi
if (( detect_rc >= 129 )); then
return "$detect_rc"
fi
if (( detect_rc != 1 )); then
return 76
fi
skipUnattended "$dir" "$iso" "$boot" || return 76 skipUnattended "$dir" "$iso" "$boot" || return 76
@@ -189,10 +167,10 @@ prepareWindowsImage() {
bootWindows() { bootWindows() {
restoreMachineState || return 1 restoreMachineState || return
restoreBootMode || return 1 restoreBootMode || return
restoreMachine || return 1 restoreMachine || return
reserveSambaPorts || return 1 reserveSambaPorts || return
return 0 return 0
} }
@@ -752,9 +730,8 @@ getArchiveSize() {
listing=$(7z l -slt "$file" 2>/dev/null) || { listing=$(7z l -slt "$file" 2>/dev/null) || {
rc=$? rc=$?
(( rc >= 129 )) && exit "$rc"
error "Failed to read archive information: $file" error "Failed to read archive information: $file"
return 1 return "$rc"
} }
while IFS= read -r line; do while IFS= read -r line; do
@@ -797,11 +774,7 @@ extractImage() {
fi fi
if [[ "${iso,,}" == *".esd" ]]; then if [[ "${iso,,}" == *".esd" ]]; then
extractESD "$iso" "$dir" "$version" "$desc" || { extractESD "$iso" "$dir" "$version" "$desc" || return
rc=$?
(( rc >= 129 )) && exit "$rc"
return 1
}
return 0 return 0
fi fi
@@ -833,7 +806,7 @@ extractImage() {
required="$size" required="$size"
if enabled "${UNPACK:-}"; then if enabled "${UNPACK:-}"; then
getArchiveSize "$iso" archiveSize || return 1 getArchiveSize "$iso" archiveSize || return
required="$archiveSize" required="$archiveSize"
fi fi
@@ -849,9 +822,8 @@ extractImage() {
7z x "$iso" -o"$target" > /dev/null || { 7z x "$iso" -o"$target" > /dev/null || {
rc=$? rc=$?
fKill "progress.sh" fKill "progress.sh"
(( rc >= 129 )) && exit "$rc"
error "Failed to extract ISO file: $iso" error "Failed to extract ISO file: $iso"
return 1 return "$rc"
} }
fKill "progress.sh" fKill "progress.sh"
@@ -897,9 +869,8 @@ extractImage() {
7z x "$iso" -o"$dir" > /dev/null || { 7z x "$iso" -o"$dir" > /dev/null || {
rc=$? rc=$?
(( rc >= 129 )) && exit "$rc"
error "Failed to extract nested ISO file: $iso" error "Failed to extract nested ISO file: $iso"
return 1 return "$rc"
} }
LABEL=$(isoinfo -d -i "$iso" | sed -n 's/Volume id: //p') || LABEL="" LABEL=$(isoinfo -d -i "$iso" | sed -n 's/Volume id: //p') || LABEL=""
@@ -915,32 +886,29 @@ detectImage() {
local dir="$1" local dir="$1"
local desc detect_rc=0 local desc rc
info "Detecting version from ISO image..." info "Detecting version from ISO image..."
# Marker-based legacy and ReactOS detection must run before looking for a WIM. # Marker-based legacy and ReactOS detection must run before looking for a WIM.
detectLegacy "$dir" || detect_rc=$? if detectLegacy "$dir"; then
if (( detect_rc == 0 )); then
desc=$(printEdition "$DETECTED" "$DETECTED" "Y") || return 2 desc=$(printEdition "$DETECTED" "$DETECTED" "Y") || return 2
info "Detected: $desc" info "Detected: $desc"
return 0 return 0
else
rc=$?
(( rc == 1 )) || return "$rc"
fi fi
(( detect_rc == 1 )) || return "$detect_rc" if detectReactOS "$dir"; then
detect_rc=0
detectReactOS "$dir" || detect_rc=$?
if (( detect_rc == 0 )); then
desc=$(printEdition "$DETECTED" "$DETECTED" "Y") || return 2 desc=$(printEdition "$DETECTED" "$DETECTED" "Y") || return 2
info "Detected: $desc" info "Detected: $desc"
return 0 return 0
else
rc=$?
(( rc == 1 )) || return "$rc"
fi fi
(( detect_rc == 1 )) || return "$detect_rc"
local wim local wim
wim=$(findImage "$dir") || return $? wim=$(findImage "$dir") || return $?
@@ -1370,11 +1338,11 @@ checkMemory() {
local id="$1" local id="$1"
local required name local required name
required=$(getRequiredMemory "$id") || return 1 required=$(getRequiredMemory "$id") || return
RAM_MINIMUM="$required" RAM_MINIMUM="$required"
name=$(printVersion "$id" "") || return 1 name=$(printVersion "$id" "") || return
checkMemoryRequirement "$name" || return 1 checkMemoryRequirement "$name" || return
return 0 return 0
} }
+99 -105
View File
@@ -126,11 +126,7 @@ downloadWindowsLink() {
--output /dev/null \ --output /dev/null \
--header "Accept:" \ --header "Accept:" \
--max-filesize 100K \ --max-filesize 100K \
-- "$vlsUrl" || { -- "$vlsUrl" || return
local rc=$?
(( rc >= 129 )) && exit "$rc"
return 1
}
# Complete Microsoft's ov-df challenge by retrieving a token and timing # Complete Microsoft's ov-df challenge by retrieving a token and timing
# value, then returning both with the current timestamp. # value, then returning both with the current timestamp.
@@ -143,11 +139,7 @@ downloadWindowsLink() {
ovData=$(curlRequest "Microsoft" "$agent" \ ovData=$(curlRequest "Microsoft" "$agent" \
--header "Accept:" \ --header "Accept:" \
--max-filesize 1M \ --max-filesize 1M \
-- "$ovUrl") || { -- "$ovUrl") || return
local rc=$?
(( rc >= 129 )) && exit "$rc"
return 1
}
if [[ $ovData =~ [\?\&]w=([A-Fa-f0-9]+) ]]; then if [[ $ovData =~ [\?\&]w=([A-Fa-f0-9]+) ]]; then
ovToken="${BASH_REMATCH[1]}" ovToken="${BASH_REMATCH[1]}"
@@ -175,11 +167,7 @@ downloadWindowsLink() {
--output /dev/null \ --output /dev/null \
--header "Accept:" \ --header "Accept:" \
--max-filesize 100K \ --max-filesize 100K \
-- "$ovUrl" || { -- "$ovUrl" || return
local rc=$?
(( rc >= 129 )) && exit "$rc"
return 1
}
enabled "$DEBUG" && echo -n "Getting language SKU ID: " enabled "$DEBUG" && echo -n "Getting language SKU ID: "
@@ -189,17 +177,13 @@ downloadWindowsLink() {
--referer "$url" \ --referer "$url" \
--header "Accept:" \ --header "Accept:" \
--max-filesize 100K \ --max-filesize 100K \
-- "$skuUrl") || { -- "$skuUrl") || return
local rc=$?
(( rc >= 129 )) && exit "$rc"
return 1
}
# Guard jq under errexit so malformed API data can be handled as a normal # Let jq parsing failures propagate so malformed API data is not mistaken
# missing-result error. The same pattern is reused for the link response. # for a normal missing-result response. The same applies to the link data.
{ skuId=$(printf '%s\n' "$skuJson" | jq --arg LANG "$language" -r 'first(.Skus[]? | select(.Language == $LANG) | .Id) // empty') 2>/dev/null; local rc=$?; } || : skuId=$(printf '%s\n' "$skuJson" | jq --arg LANG "$language" -r 'first(.Skus[]? | select(.Language == $LANG) | .Id) // empty') 2>/dev/null || return
if [ -z "$skuId" ] || [[ "${skuId,,}" == "null" ]] || (( rc != 0 )); then if [ -z "$skuId" ] || [[ "${skuId,,}" == "null" ]]; then
language=$(getLanguage "$lang" "desc") language=$(getLanguage "$lang" "desc")
error "No download in the $language language available for $desc!" error "No download in the $language language available for $desc!"
return 1 return 1
@@ -217,11 +201,7 @@ downloadWindowsLink() {
--referer "$url" \ --referer "$url" \
--header "Accept:" \ --header "Accept:" \
--max-filesize 100K \ --max-filesize 100K \
-- "$linkUrl") || { -- "$linkUrl") || return
local rc=$?
(( rc >= 129 )) && exit "$rc"
return 1
}
if ! [ "$linkJson" ]; then if ! [ "$linkJson" ]; then
error "Microsoft servers gave us an empty response to our request for an automated download." error "Microsoft servers gave us an empty response to our request for an automated download."
@@ -238,9 +218,9 @@ downloadWindowsLink() {
return 1 return 1
fi fi
{ link=$(printf '%s\n' "$linkJson" | jq --argjson TYPE "$type" -r 'first(.ProductDownloadOptions[]? | select(.DownloadType == $TYPE) | .Uri) // empty') 2>/dev/null; rc=$?; } || : link=$(printf '%s\n' "$linkJson" | jq --argjson TYPE "$type" -r 'first(.ProductDownloadOptions[]? | select(.DownloadType == $TYPE) | .Uri) // empty') 2>/dev/null || return
if [ -z "$link" ] || [[ "${link,,}" == "null" ]] || (( rc != 0 )); then if [ -z "$link" ] || [[ "${link,,}" == "null" ]]; then
error "Microsoft server gave us no download link to our request for an automated download!" error "Microsoft server gave us no download link to our request for an automated download!"
info "Response: $linkJson" info "Response: $linkJson"
return 1 return 1
@@ -256,7 +236,7 @@ downloadWindows() {
local lang="$2" local lang="$2"
local desc="$3" local desc="$3"
local agent language page local agent language page rc
local productId type winVer local productId type winVer
agent=$(getAgent) agent=$(getAgent)
@@ -287,9 +267,12 @@ downloadWindows() {
if downloadWindowsLink "$productId" "$url" "$agent" "$language" "$lang" "$desc" "$type"; then if downloadWindowsLink "$productId" "$url" "$agent" "$language" "$lang" "$desc" "$type"; then
return 0 return 0
else
rc=$?
(( rc == 1 )) || return "$rc"
fi fi
sleep 1 sleep 1 || return
# Product edition IDs can change. If the configured ID fails, recover the # Product edition IDs can change. If the configured ID fails, recover the
# current value from Microsoft's public download page and retry once. # current value from Microsoft's public download page and retry once.
@@ -300,11 +283,7 @@ downloadWindows() {
page=$(curlRequest "Microsoft" "$agent" \ page=$(curlRequest "Microsoft" "$agent" \
--header "Accept:" \ --header "Accept:" \
--max-filesize 1M \ --max-filesize 1M \
-- "$url") || { -- "$url") || return
local rc=$?
(( rc >= 129 )) && exit "$rc"
return 1
}
enabled "$DEBUG" && echo -n "Getting Product edition ID: " enabled "$DEBUG" && echo -n "Getting Product edition ID: "
productId=$(printf '%s' "$page" | productId=$(printf '%s' "$page" |
@@ -312,7 +291,7 @@ downloadWindows() {
grep -Eio "<option[^>]*value=[\"'][0-9]+[\"'][^>]*>[[:space:]]*Windows[^<]*" | grep -Eio "<option[^>]*value=[\"'][0-9]+[\"'][^>]*>[[:space:]]*Windows[^<]*" |
sed -nE "s/.*value=[\"']([0-9]+)[\"'].*/\1/p" | sed -nE "s/.*value=[\"']([0-9]+)[\"'].*/\1/p" |
sed -n '1p' | sed -n '1p' |
cut -c 1-16 || true) cut -c 1-16) || return
enabled "$DEBUG" && echo "$productId" enabled "$DEBUG" && echo "$productId"
if [ -z "$productId" ]; then if [ -z "$productId" ]; then
@@ -320,9 +299,7 @@ downloadWindows() {
return 1 return 1
fi fi
if ! downloadWindowsLink "$productId" "$url" "$agent" "$language" "$lang" "$desc" "$type"; then downloadWindowsLink "$productId" "$url" "$agent" "$language" "$lang" "$desc" "$type" || return
return 1
fi
return 0 return 0
} }
@@ -334,12 +311,9 @@ downloadWindowsEval() {
local desc="$3" local desc="$3"
local compare compare_name link_name local compare compare_name link_name
local agent culture language type winVer local agent culture language type winVer rc
case "${id,,}" in case "${id,,}" in
"win10${PLATFORM,,}-enterprise-eval" )
type="enterprise"
winVer="windows-10-enterprise" ;;
"win11${PLATFORM,,}-enterprise-eval" ) "win11${PLATFORM,,}-enterprise-eval" )
type="enterprise" type="enterprise"
winVer="windows-11-enterprise" ;; winVer="windows-11-enterprise" ;;
@@ -385,11 +359,7 @@ downloadWindowsEval() {
page=$(curlRequest "Microsoft" "$agent" \ page=$(curlRequest "Microsoft" "$agent" \
--location \ --location \
--max-filesize 1M \ --max-filesize 1M \
-- "$url") || { -- "$url") || return
local rc=$?
(( rc >= 129 )) && exit "$rc"
return 1
}
if ! [ "$page" ]; then if ! [ "$page" ]; then
error "Evaluation Center download page gave us an empty response" error "Evaluation Center download page gave us an empty response"
@@ -438,8 +408,8 @@ downloadWindowsEval() {
--write-out "%{redirect_url}" \ --write-out "%{redirect_url}" \
--head \ --head \
-- "$candidate") || { -- "$candidate") || {
local rc=$? rc=$?
(( rc >= 129 )) && exit "$rc" (( rc == 1 )) || return "$rc"
continue continue
} }
@@ -531,11 +501,7 @@ downloadWindowsEval() {
--output /dev/null \ --output /dev/null \
--write-out "%{url_effective}" \ --write-out "%{url_effective}" \
--head \ --head \
-- "$link") || { -- "$link") || return
local rc=$?
(( rc >= 129 )) && exit "$rc"
return 1
}
local lower="${link,,}" local lower="${link,,}"
local separator='(^|[[:space:]_./-])' local separator='(^|[[:space:]_./-])'
@@ -640,7 +606,7 @@ downloadWindowsLtsc() {
local lang="$2" local lang="$2"
local desc="$3" local desc="$3"
local alternate alternate_desc local alternate alternate_desc rc
case "${id,,}" in case "${id,,}" in
"win11${PLATFORM,,}-enterprise-iot-eval" ) "win11${PLATFORM,,}-enterprise-iot-eval" )
@@ -657,19 +623,21 @@ downloadWindowsLtsc() {
if downloadWindowsEval "$id" "$lang" "$desc" > /dev/null 2>&1; then if downloadWindowsEval "$id" "$lang" "$desc" > /dev/null 2>&1; then
MIDO_SOURCE="$id" MIDO_SOURCE="$id"
return 0 return 0
else
rc=$?
(( rc == 1 )) || return "$rc"
fi fi
alternate_desc=$(printEdition "$alternate" "$alternate" "Y") alternate_desc=$(printEdition "$alternate" "$alternate" "Y")
info "Primary download source failed, trying $alternate_desc instead..." info "Primary download source failed, trying $alternate_desc instead..."
if downloadWindowsEval "$alternate" "$lang" "$alternate_desc"; then downloadWindowsEval "$alternate" "$lang" "$alternate_desc" || return
MIDO_SOURCE="$alternate" MIDO_SOURCE="$alternate"
warn "the requested $desc was unavailable, using $alternate_desc instead." warn "the requested $desc was unavailable, using $alternate_desc instead."
return 0
fi
return 1 return 0
} }
getWindows() { getWindows() {
@@ -679,7 +647,7 @@ getWindows() {
local desc="$3" local desc="$3"
local web_desc="$4" local web_desc="$4"
local language edition local language edition rc
MIDO_SOURCE="" MIDO_SOURCE=""
MIDO_STATIC="N" MIDO_STATIC="N"
@@ -727,19 +695,29 @@ getWindows() {
if downloadWindows "$version" "$lang" "$edition"; then if downloadWindows "$version" "$lang" "$edition"; then
MIDO_SOURCE="$version" MIDO_SOURCE="$version"
return 0 return 0
else
rc=$?
(( rc == 1 )) || return "$rc"
fi ;; fi ;;
"win11${PLATFORM,,}-enterprise-iot-eval" | \ "win11${PLATFORM,,}-enterprise-iot-eval" | \
"win11${PLATFORM,,}-enterprise-ltsc-eval" ) "win11${PLATFORM,,}-enterprise-ltsc-eval" )
downloadWindowsLtsc "$version" "$lang" "$edition" && return 0 ;; if downloadWindowsLtsc "$version" "$lang" "$edition"; then
return 0
else
rc=$?
(( rc == 1 )) || return "$rc"
fi ;;
"win10${PLATFORM,,}-enterprise-eval" | \
"win11${PLATFORM,,}-enterprise"* ) "win11${PLATFORM,,}-enterprise"* )
if downloadWindowsEval "$version" "$lang" "$edition"; then if downloadWindowsEval "$version" "$lang" "$edition"; then
MIDO_SOURCE="$version" MIDO_SOURCE="$version"
return 0 return 0
else
rc=$?
(( rc == 1 )) || return "$rc"
fi ;; fi ;;
"win2025-eval" | "win2022-eval" | "win2019-eval" | \ "win2025-eval" | "win2022-eval" | "win2019-eval" | \
@@ -748,6 +726,9 @@ getWindows() {
if downloadWindowsEval "$version" "$lang" "$edition"; then if downloadWindowsEval "$version" "$lang" "$edition"; then
MIDO_SOURCE="$version" MIDO_SOURCE="$version"
return 0 return 0
else
rc=$?
(( rc == 1 )) || return "$rc"
fi ;; fi ;;
"win2008r2"*| "win81${PLATFORM,,}"* | "win10${PLATFORM,,}-enterprise"* ) ;; "win2008r2"*| "win81${PLATFORM,,}"* | "win10${PLATFORM,,}-enterprise"* ) ;;
@@ -1077,7 +1058,10 @@ getESD() {
local msg="Downloading ESD catalog..." local msg="Downloading ESD catalog..."
info "$msg" && html "$msg" info "$msg" && html "$msg"
rm -rf "$dir" if ! rm -rf "$dir"; then
error "Failed to remove directory \"$dir\" !"
return 1
fi
if ! makeDir "$dir"; then if ! makeDir "$dir"; then
error "Failed to create directory \"$dir\" !" error "Failed to create directory \"$dir\" !"
@@ -1118,7 +1102,7 @@ getESD() {
rm -f "$log" rm -f "$log"
if (( rc >= 129 )); then if (( rc >= 129 )); then
exit "$rc" return "$rc"
fi fi
return 1 return 1
@@ -1160,8 +1144,7 @@ getESD() {
validateESDCatalog "$dir/$xmlFile" "$provider" || return 1 validateESDCatalog "$dir/$xmlFile" "$provider" || return 1
fi fi
if ! parseESD \ if ! parseESD "$dir/$xmlFile" "$version" "$lang" "$desc" "$edition" "$culture"; then
"$dir/$xmlFile" "$version" "$lang" "$desc" "$edition" "$culture"; then
return 1 return 1
fi fi
@@ -1222,26 +1205,16 @@ verifyFile() {
hash=$(sha1sum "$iso" | cut -f1 -d' ') || { hash=$(sha1sum "$iso" | cut -f1 -d' ') || {
local rc=$? local rc=$?
if (( rc >= 129 )); then
exit "$rc"
fi
error "Failed to calculate SHA1 checksum for $iso!" error "Failed to calculate SHA1 checksum for $iso!"
return 1 return "$rc"
} }
else else
hash=$(sha256sum "$iso" | cut -f1 -d' ') || { hash=$(sha256sum "$iso" | cut -f1 -d' ') || {
local rc=$? local rc=$?
if (( rc >= 129 )); then
exit "$rc"
fi
error "Failed to calculate SHA256 checksum for $iso!" error "Failed to calculate SHA256 checksum for $iso!"
return 1 return "$rc"
} }
fi fi
@@ -1315,7 +1288,7 @@ tryDownload() {
minimum="10485760" minimum="10485760"
fi fi
if downloadRetry \ downloadRetry \
"$iso" \ "$iso" \
"${CONNECTIONS:-1}" \ "${CONNECTIONS:-1}" \
"$seconds" \ "$seconds" \
@@ -1325,17 +1298,7 @@ tryDownload() {
"$url" \ "$url" \
"$size" \ "$size" \
"$desc" \ "$desc" \
"$web_desc"; then "$web_desc" || return
local rc=0
else
local rc=$?
fi
if (( rc >= 129 )); then
exit "$rc"
fi
(( rc == 0 )) || return "$rc"
# The shared helper already inspected the file, so this should # The shared helper already inspected the file, so this should
# only fail if the downloaded file was removed unexpectedly afterward. # only fail if the downloaded file was removed unexpectedly afterward.
@@ -1345,12 +1308,15 @@ tryDownload() {
fi fi
# Status 2 means the completed download failed deterministic validation. # Status 2 means the completed download failed deterministic validation.
if ! verifyFile "$iso" "$size" "$total" "$sum"; then verifyFile "$iso" "$size" "$total" "$sum" || {
local rc=$?
(( rc == 1 )) || return "$rc"
if ! rm -f -- "$iso" "$iso.aria2"; then if ! rm -f -- "$iso" "$iso.aria2"; then
warn "failed to remove invalid download \"$iso\"!" warn "failed to remove invalid download \"$iso\"!"
fi fi
return 2 return 2
fi }
# Extract the .iso from the compressed archive if needed. # Extract the .iso from the compressed archive if needed.
isCompressed "$url" && UNPACK="Y" isCompressed "$url" && UNPACK="Y"
@@ -1379,7 +1345,7 @@ fallbackEnglish() {
# still locate the same image, but use English installation media. # still locate the same image, but use English installation media.
LANGUAGE="en" LANGUAGE="en"
removeImage "$iso" || return 1 removeImage "$iso" || return
downloadImage "$iso" "$version" "$LANGUAGE" downloadImage "$iso" "$version" "$LANGUAGE"
} }
@@ -1410,7 +1376,7 @@ downloadImage() {
local detected="$DETECTED" local detected="$DETECTED"
local requested="$version" switched="" local requested="$version" switched=""
local tried="n" success="n" seconds="5" local tried="n" success="n" seconds="5"
local i url sum size base language desc web_desc metadata local i url sum size base language desc web_desc metadata rc
if [[ "${version,,}" == "http"* ]]; then if [[ "${version,,}" == "http"* ]]; then
@@ -1418,7 +1384,7 @@ downloadImage() {
desc=$(fromFile "$base") desc=$(fromFile "$base")
web_desc="$desc" web_desc="$desc"
tryDownload "$iso" "$version" "" "" "$desc" "$seconds" "$web_desc" || return 1 tryDownload "$iso" "$version" "" "" "$desc" "$seconds" "$web_desc" || return
return 0 return 0
fi fi
@@ -1437,7 +1403,7 @@ downloadImage() {
web_desc=$(printEdition "$version" "$web_desc") web_desc=$(printEdition "$version" "$web_desc")
desc+=" in $language" desc+=" in $language"
fallbackEnglish "$iso" "$version" "$lang" "$desc" || return 1 fallbackEnglish "$iso" "$version" "$lang" "$desc" || return
return 0 return 0
fi fi
@@ -1455,8 +1421,17 @@ downloadImage() {
if getWindows "$version" "$lang" "$desc" "$web_desc"; then if getWindows "$version" "$lang" "$desc" "$web_desc"; then
success="y" success="y"
else else
delay "$seconds" rc=$?
getWindows "$version" "$lang" "$desc" "$web_desc" && success="y" (( rc == 1 )) || return "$rc"
delay "$seconds" || return
if getWindows "$version" "$lang" "$desc" "$web_desc"; then
success="y"
else
rc=$?
(( rc == 1 )) || return "$rc"
fi
fi fi
if [[ "$success" == "y" ]]; then if [[ "$success" == "y" ]]; then
@@ -1483,6 +1458,9 @@ downloadImage() {
# Commit the candidate only after the image was downloaded and verified. # Commit the candidate only after the image was downloaded and verified.
DETECTED="$detected" DETECTED="$detected"
return 0 return 0
else
rc=$?
(( rc == 1 || rc == 2 )) || return "$rc"
fi fi
fi fi
@@ -1520,7 +1498,15 @@ downloadImage() {
if getESD "$TMP/esd" "$version" "$lang" "$desc"; then if getESD "$TMP/esd" "$version" "$lang" "$desc"; then
success="y" success="y"
else else
getESD "$TMP/esd" "$version" "$lang" "$desc" "wor" && success="y" rc=$?
(( rc == 1 )) || return "$rc"
if getESD "$TMP/esd" "$version" "$lang" "$desc" "wor"; then
success="y"
else
rc=$?
(( rc == 1 )) || return "$rc"
fi
fi fi
if [[ "$success" == "y" ]]; then if [[ "$success" == "y" ]]; then
@@ -1531,6 +1517,9 @@ downloadImage() {
if tryDownload "$ISO" "$ESD" "$ESD_SUM" "$ESD_SIZE" "$desc" "$seconds" "$web_desc"; then if tryDownload "$ISO" "$ESD" "$ESD_SUM" "$ESD_SIZE" "$desc" "$seconds" "$web_desc"; then
return 0 return 0
else
rc=$?
(( rc == 1 || rc == 2 )) || return "$rc"
fi fi
ISO="$iso" ISO="$iso"
@@ -1552,14 +1541,19 @@ downloadImage() {
size=$(getSize "$i" "$version" "$lang") size=$(getSize "$i" "$version" "$lang")
sum=$(getHash "$i" "$version" "$lang") sum=$(getHash "$i" "$version" "$lang")
tryDownload "$iso" "$url" "$sum" "$size" "$desc" "$seconds" "$web_desc" && return 0 if tryDownload "$iso" "$url" "$sum" "$size" "$desc" "$seconds" "$web_desc"; then
return 0
else
rc=$?
(( rc == 1 || rc == 2 )) || return "$rc"
fi
fi fi
done done
if [[ "${lang,,}" != "en" && "${lang,,}" != "en-"* ]]; then if [[ "${lang,,}" != "en" && "${lang,,}" != "en-"* ]]; then
fallbackEnglish "$iso" "$requested" "$lang" "$desc" || return 1 fallbackEnglish "$iso" "$requested" "$lang" "$desc" || return
return 0 return 0
fi fi