1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
|
#!/usr/bin/env python
"""A program to show using iso9660 to extract a file from an ISO-9660
image.
If a single argument is given, it is used as the ISO 9660 image to use
in the extraction. Otherwise a compiled in default ISO 9660 image name
(that comes with the libcdio distribution) will be used. A program to
show using iso9660 to extract a file from an ISO-9660 image."""
#
# Copyright (C) 2006, 2008, 2013, 2021 Rocky Bernstein <rocky@gnu.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os, sys
libdir = os.path.join(os.path.dirname(__file__), "..")
if libdir[-1] != os.path.sep:
libdir += os.path.sep
sys.path.insert(0, libdir)
import pycdio
import iso9660
PY3 = sys.version_info[0] == 3
# Python has rounding (round) and trucation (int), but what about an integer
# ceiling function? Until I learn what it is...
def ceil(x):
return int(round(x + 0.5))
# The default CD image if none given
iso_image_path = "../data"
iso_image_fname = os.path.join(iso_image_path, "isofs-m1.cue")
# File to extract if none given.
iso9660_path = "/"
local_filename = "COPYING"
if len(sys.argv) > 1:
iso_image_fname = sys.argv[1]
if len(sys.argv) > 2:
local_filename = sys.argv[1]
if len(sys.argv) > 3:
print(
"""
usage: %s [CD-ROM-or-image [filename]]
Extracts filename from CD-ROM-or-image.
"""
% sys.argv[0]
)
sys.exit(1)
try:
iso = iso9660.ISO9660.FS(source=iso_image_fname)
except:
print("Sorry, couldn't open %s as a ISO9660 CD image." % iso_image_fname)
sys.exit(1)
statbuf = iso.stat(local_filename, False)
if statbuf is None:
print(
'Could not get ISO-9660 file information for file "%s" in "%s"'
% (local_filename, iso_image_fname)
)
file_stats = iso.readdir("/")
print("Top-level names:")
for stat in file_stats:
filename = stat[0]
print("%s" % filename)
iso.close()
sys.exit(2)
try:
OUTPUT = os.open(local_filename, os.O_CREAT | os.O_WRONLY, 0o664)
except:
print("Can't open %s for writing" % local_filename)
# Copy the blocks from the ISO-9660 filesystem to the local filesystem.
blocks = ceil(statbuf["size"] / pycdio.ISO_BLOCKSIZE)
for i in range(blocks):
lsn = statbuf["LSN"] + i
size, buf = iso.read_data_blocks(lsn)
if size < 0:
print("Error reading ISO 9660 file %s at LSN %d" % (local_filename, lsn))
sys.exit(4)
pass
if PY3:
os.write(OUTPUT, bytes(buf, "UTF-8"))
else:
os.write(OUTPUT, buf)
pass
# Make sure the file size has the exact same byte size. Without the
# truncate below, the file will a multiple of ISO_BLOCKSIZE.
os.ftruncate(OUTPUT, statbuf["size"])
print("Extraction of file '%s' from %s successful." % (local_filename, iso_image_fname))
os.close(OUTPUT)
iso.close()
sys.exit(0)
|