#!/bin/sh # # Derive SOURCE_DATE_EPOCH for VeraCrypt build and packaging paths. # Precedence inside this helper is git HEAD, then the release date encoded in # Common/Tcdefs.h. Callers remain responsible for honoring an explicit # SOURCE_DATE_EPOCH before invoking this helper. The source root is resolved # before probing Git so symlinked build paths still use the checkout HEAD, # while release tarballs unpacked below unrelated repositories ignore the # parent repository and fall back to Common/Tcdefs.h. if [ "$#" -ne 1 ]; then echo "Usage: $0 " >&2 exit 2 fi SOURCE_ROOT_INPUT=${1%/} if [ -z "$SOURCE_ROOT_INPUT" ]; then SOURCE_ROOT_INPUT=/ fi SOURCE_ROOT=$(cd "$SOURCE_ROOT_INPUT" 2>/dev/null && pwd -P) || { echo "Error: $1 is not a readable directory" >&2 exit 1 } TCDEFS_H="$SOURCE_ROOT/Common/Tcdefs.h" GIT_WORKTREE= GIT_SOURCE_PREFIX= SOURCE_ROOT_BASENAME=${SOURCE_ROOT##*/} if [ -e "$SOURCE_ROOT/.git" ]; then GIT_WORKTREE="$SOURCE_ROOT" elif [ -e "$SOURCE_ROOT/../.git" ]; then GIT_WORKTREE=$(cd "$SOURCE_ROOT/.." 2>/dev/null && pwd -P) GIT_SOURCE_PREFIX="$SOURCE_ROOT_BASENAME/" fi GIT_EPOCH= if [ -n "$GIT_WORKTREE" ] && (cd "$GIT_WORKTREE" && git rev-parse --is-inside-work-tree >/dev/null 2>&1 && git ls-files --error-unmatch \ "${GIT_SOURCE_PREFIX}Common/Tcdefs.h" \ "${GIT_SOURCE_PREFIX}Build/Tools/source_date_epoch.sh" >/dev/null 2>&1); then GIT_EPOCH=$(cd "$GIT_WORKTREE" && git log -1 --pretty=%ct 2>/dev/null) fi case "$GIT_EPOCH" in ''|*[!0-9]*) ;; *) printf '%s\n' "$GIT_EPOCH" exit 0 ;; esac if [ ! -r "$TCDEFS_H" ]; then echo "Error: $TCDEFS_H is not readable" >&2 exit 1 fi RELEASE_EPOCH=$(awk ' function leap(y) { return ((y % 4 == 0 && y % 100 != 0) || (y % 400 == 0)) } function month_number(name) { return (name == "January" ? 1 : name == "February" ? 2 : name == "March" ? 3 : name == "April" ? 4 : name == "May" ? 5 : name == "June" ? 6 : name == "July" ? 7 : name == "August" ? 8 : name == "September" ? 9 : name == "October" ? 10 : name == "November" ? 11 : name == "December" ? 12 : 0); } function mdays(m, y) { return (m == 2 ? 28 + leap(y) : (m == 4 || m == 6 || m == 9 || m == 11 ? 30 : 31)) } function epoch(y, m, d, days, i) { days = 0; for (i = 1970; i < y; i++) days += 365 + leap(i); for (i = 1; i < m; i++) days += mdays(i, y); days += d - 1; return days * 86400; } function is_number(value) { return (value ~ /^[0-9]+$/) } /^[[:space:]]*#define[[:space:]]+TC_STR_RELEASE_DATE[[:space:]]+L"/ { date = $0; sub(/^.*L"/, "", date); sub(/".*$/, "", date); split(date, parts, /[ ,]+/); if (month_number(parts[1]) == 0 || !is_number(parts[2]) || !is_number(parts[3])) exit 1; date_month = month_number(parts[1]); date_day = parts[2] + 0; date_year = parts[3] + 0; seen_date = 1; } /^[[:space:]]*#define[[:space:]]+TC_RELEASE_DATE_YEAR[[:space:]]+/ { if (!is_number($3)) exit 1; year = $3 + 0; seen_year = 1; } /^[[:space:]]*#define[[:space:]]+TC_RELEASE_DATE_MONTH[[:space:]]+/ { if (!is_number($3)) exit 1; month = $3 + 0; seen_month = 1; } /^[[:space:]]*#define[[:space:]]+TC_RELEASE_DATE_DAY[[:space:]]+/ { if (!is_number($3)) exit 1; day = $3 + 0; seen_day = 1; } END { if (!seen_date || !seen_year || !seen_month || !seen_day) exit 1; if (year < 1970 || month < 1 || month > 12 || day < 1 || day > mdays(month, year)) exit 1; if (date_month != month || date_day != day || date_year != year) exit 1; printf "%d", epoch(year, month, day); }' "$TCDEFS_H") || { echo "Error: unable to derive SOURCE_DATE_EPOCH from $TCDEFS_H" >&2 exit 1 } case "$RELEASE_EPOCH" in ''|*[!0-9]*) echo "Error: unable to derive SOURCE_DATE_EPOCH from $TCDEFS_H" >&2 exit 1 ;; esac printf '%s\n' "$RELEASE_EPOCH"