#! /bin/sh
# Midnight Commander - ISO9660 VFS for MC
# based on lslR by Tomas Novak <tnovak@ipex.cz> April 2000
#
# Copyright (C) 2000, 2003
# The Free Software Foundation, Inc.
#
# Written by:
# Michael Shigorin <mike@altlinux.org>,
# Grigory Milev <week@altlinux.org>,
# Kachalov Anton <mouse@linux.ru.net>, 2003
# Victor Ananjevsky <ananasik@gmail.com>, 2013
# slava zanko <slavazanko@gmail.com>, 2013
# slowpeek <slowpeek@users.noreply.github.com>, 2024
#
# This file is part of the Midnight Commander.
#
# The Midnight Commander is free software: you can redistribute it
# and/or modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation, either version 3 of the License,
# or (at your option) any later version.
#
# The Midnight Commander is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#*** include section (source functions, for example) *******************
#*** file scope functions **********************************************
XORRISO=`command -v xorriso 2>/dev/null`
# This snippet is used to undo xorriso's Text_shellsafe(). Pseudocode for the
# function:
#
# Text_shellsafe( s) {
# return q(') replace(q('), q('"'"'), s) q(')
# }
#
# Xorriso_ls() uses two formats for pathes:
# - generic: Text_shellsafe(path)
# - symlink: Text_shellsafe(link) q( -> ) Text_shellsafe(target)
#
# References in xorriso sources:
# - iso_tree.c:Xorriso_ls()
# - text_io.c:Xorriso_esc_filepath()
# - misc_funct.c:Text_shellsafe()
awk_xorriso_unesc=`cat <<'EOF'
{
# Start of the path part
i = index($0, "'")
s = substr($0, i)
# The path part with the wrapping quotes removed
s = substr(s, 2, length(s)-2)
if (substr($0, 1, 1) == "l") {
s1=s
if (gsub("->", "", s1) > 1) {
# Ambiguity: either the link or its target contains q(->) in
# addition to the link/target delimiter
next
}
j = index(s, "' -> '")
# link -> target with the wrapping quotes removed from both
s = substr(s, 1, j-1) " -> " substr(s, j+6)
} else if (index(s, "->")) {
# Ambiguity: not a symlink, but there is q(->)
next
}
gsub("'\"'\"'", "'", s)
print substr($0, 1, i-1) s
}
EOF
`
xorriso_list() (
if test -z "$XORRISO"; then
return 1
fi
temp_ls=`mktemp "${MC_TMPDIR:-/tmp}"/mc-iso9660.XXXXXX` || return 1
# $XORRISO must be unquoted here to hook into the testing framework
$XORRISO -abort_on FATAL -dev stdio:"$1" -find / -exec lsdl 2>/dev/null >"$temp_ls"
r=$?
if [ "$r" != 0 ]; then
rm -f "$temp_ls"
return "$r"
fi
# The first line is /, skip it
sed 1,1d "$temp_ls" |
# disk_ops.c:Xorriso_format_ls_l() prints the boot catalog file as of
# type "e". Make it a generic file
sed 's,^e,-,' |
@AWK@ "$awk_xorriso_unesc"
rm -f "$temp_ls"
)
xorriso_copyout() {
if test -z "$XORRISO"; then
return 1
fi
$XORRISO -dev stdio:"$1" -osirrox on -extract "$2" "$3" >/dev/null 2>&1
}
xorriso_copyin() {
if test -z "$XORRISO"; then
return 1
fi
$XORRISO -dev stdio:"$1" -cpr "$3" "$2" >/dev/null 2>&1
}
xorriso_mkdir() {
if test -z "$XORRISO"; then
return 1
fi
$XORRISO -dev stdio:"$1" -mkdir "$2" >/dev/null 2>&1
}
xorriso_rmdir() {
if test -z "$XORRISO"; then
return 1
fi
$XORRISO -dev stdio:"$1" -rmdir "$2" >/dev/null 2>&1
}
xorriso_rm() {
if test -z "$XORRISO"; then
return 1
fi
$XORRISO -dev stdio:"$1" -rm "$2" >/dev/null 2>&1
}
# tested to comply with isoinfo 2.0's output
test_iso () {
ISOINFO=`command -v isoinfo 2>/dev/null`
if test -z "$ISOINFO"; then
echo "isoinfo not found" >&2
return 1
fi
CHARSET=`locale charmap 2>/dev/null`
if test -z "$CHARSET"; then
CHARSET=`locale 2>/dev/null | grep LC_CTYPE | sed -n -e 's/.*\.\(.*\)"$/\1/p'`
fi
if test -n "$CHARSET"; then
CHARSET=`echo "$CHARSET" | tr '[A-Z]' '[a-z]' | sed -e 's/^iso-/iso/'`
$ISOINFO -j "$CHARSET" -i /dev/null 2>&1 | grep "Iconv not yet supported\|Unknown charset" >/dev/null && CHARSET=
fi
if test -n "$CHARSET"; then
JOLIET_OPT="-j $CHARSET -J"
else
JOLIET_OPT="-J"
fi
ISOINFO_D_I=`$ISOINFO -d -i "$1" 2>/dev/null`
ISOINFO="$ISOINFO -R"
echo "$ISOINFO_D_I" | grep "UCS level 1\|NO Joliet" > /dev/null || ISOINFO="$ISOINFO $JOLIET_OPT"
if [ `echo "$ISOINFO_D_I" | grep "Joliet with UCS level 3 found" | wc -l` = 1 \
-a `echo "$ISOINFO_D_I" | grep "NO Rock Ridge" | wc -l` = 1 ] ; then
SEMICOLON="YES"
fi
}
mcisofs_list () (
# left as a reminder to implement compressed image support =)
case "$1" in
*.lz) MYCAT="lzip -dc";;
*.lz4) MYCAT="lz4 -dc";;
*.lzma) MYCAT="lzma -dc";;
*.lzo) MYCAT="lzop -dc";;
*.xz) MYCAT="xz -dc";;
*.zst) MYCAT="zstd -dc";;
*.bz2) MYCAT="bzip2 -dc";;
*.gz) MYCAT="gzip -dc";;
*.z) MYCAT="gzip -dc";;
*.Z) MYCAT="gzip -dc";;
*) MYCAT="cat";;
esac
lsl=`$ISOINFO -l -i "$1" 2>/dev/null`
r=$?
test $r -gt 0 && return $r
echo "$lsl" | @AWK@ -v SEMICOLON=$SEMICOLON '
BEGIN {
dir="";
# Pattern to match 8 first fields.
rx = "[^ ]+[ ]+";
rx = "^" rx rx rx rx rx rx rx rx;
irx = "^\\[ *-?[0-9]* *[0-9]+\\] +";
}
/^$/ { next }
/^d---------/ { next }
/^Directory listing of [^ ].*$/ {
dir=substr($0, 23);
next;
}
{ $11 != "" } {
name=$0
sub(rx, "", name)
attr=substr($0, 1, length($0)-length(name))
# strip inodes and extra dir entries; fix perms
sub(irx, "", name)
sub("^---------- 0 0 0", "-r--r--r-- 1 0 0 ", attr)
sub(" $", "", name)
# for Joliet UCS level 3
if (SEMICOLON == "YES") sub(";1$", "", name);
## sub(";[0-9]+$", "", name) ## would break copyout
# skip . and ..
if (name == ".") next;
if (name == "..") next;
printf "%s%s%s\n", attr, dir, name
}'
)
mcisofs_copyout () {
if [ "x$SEMICOLON" = "xYES" ]; then
$ISOINFO -i "$1" -x "/$2;1" 2>/dev/null > "$3"
else
$ISOINFO -i "$1" -x "/$2" 2>/dev/null > "$3"
fi
}
#*** main code *********************************************************
LC_ALL=C
cmd="$1"
shift
case "$cmd" in
list)
if [ -n "${MC_TEST_EXTFS_LIST_CMD:-}" ]; then
case "${MC_TEST_EXTFS_ISO9660_TOOL}" in
xorriso)
XORRISO="$MC_TEST_EXTFS_LIST_CMD"
xorriso_list "$@" || exit 1
;;
*)
exit 1
;;
esac
exit 0
fi
xorriso_list "$@" || {
test_iso "$@" || exit 1
mcisofs_list "$@" || exit 1
}
exit 0
;;
rm)
xorriso_rm "$@" || {
exit 1
}
exit 0
;;
rmdir)
xorriso_rmdir "$@" || {
exit 1
}
exit 0
;;
mkdir)
xorriso_mkdir "$@" || {
exit 1
}
exit 0
;;
copyin)
xorriso_copyin "$@" || {
exit 1
}
exit 0
;;
copyout)
xorriso_copyout "$@" || {
test_iso "$@" || exit 1
mcisofs_copyout "$@" || exit 1
}
exit 0
;;
esac
exit 1