This commit also includes: - whitespace / code formatting fixes - slight syntax related changes: except <exception_name>, e -> except <exception_name> as e - 3 pointless instructions instances have been rewritten [sorted] (spotted by semi-automatic check) The unrelated changes shouldn't have any real impact on whipper's behaviour.
123 lines
3.3 KiB
Python
123 lines
3.3 KiB
Python
import os
|
|
import re
|
|
import tempfile
|
|
from subprocess import Popen, PIPE
|
|
|
|
from whipper.common.common import EjectError
|
|
from whipper.image.toc import TocFile
|
|
|
|
import logging
|
|
logger = logging.getLogger(__name__)
|
|
|
|
CDRDAO = 'cdrdao'
|
|
|
|
|
|
def read_toc(device, fast_toc=False):
|
|
"""Get the cd's toc using cdrdao and parse it.
|
|
|
|
:param device: optical disk drive.
|
|
:type device:
|
|
:param fast_toc: enable cdrdao's fast-toc option? (Default value = False)
|
|
:type fast_toc: bool
|
|
:returns:
|
|
:rtype: TocFile
|
|
"""
|
|
# cdrdao MUST be passed a non-existing filename as its last argument
|
|
# to write the TOC to; it does not support writing to stdout or
|
|
# overwriting an existing file, nor does linux seem to support
|
|
# locking a non-existant file. Thus, this race-condition introducing
|
|
# hack is carried from morituri to whipper and will be removed when
|
|
# cdrdao is fixed.
|
|
fd, tocfile = tempfile.mkstemp(suffix=u'.cdrdao.read-toc.whipper')
|
|
os.close(fd)
|
|
os.unlink(tocfile)
|
|
|
|
cmd = [CDRDAO, 'read-toc'] + (['--fast-toc'] if fast_toc else []) + [
|
|
'--device', device, tocfile]
|
|
# PIPE is the closest to >/dev/null we can get
|
|
logger.debug("executing %r", cmd)
|
|
p = Popen(cmd, stdout=PIPE, stderr=PIPE)
|
|
_, stderr = p.communicate()
|
|
if p.returncode != 0:
|
|
msg = 'cdrdao read-toc failed: return code is non-zero: ' + \
|
|
str(p.returncode)
|
|
logger.critical(msg)
|
|
# Gracefully handle missing disc
|
|
if "ERROR: Unit not ready, giving up." in stderr:
|
|
raise EjectError(device, "no disc detected")
|
|
raise IOError(msg)
|
|
|
|
toc = TocFile(tocfile)
|
|
toc.parse()
|
|
os.unlink(tocfile)
|
|
return toc
|
|
|
|
|
|
def DetectCdr(device):
|
|
"""Check if inserted disk is a CD-R.
|
|
|
|
:param device: optical disk drive.
|
|
:type device:
|
|
:returns: False if inserted disk is not a CD-R, True otherwise.
|
|
:rtype: bool
|
|
"""
|
|
cmd = [CDRDAO, 'disk-info', '-v1', '--device', device]
|
|
logger.debug("executing %r", cmd)
|
|
p = Popen(cmd, stdout=PIPE, stderr=PIPE)
|
|
if 'CD-R medium : n/a' in p.stdout.read():
|
|
return False
|
|
else:
|
|
return True
|
|
|
|
|
|
def version():
|
|
"""Detect cdrdao's version.
|
|
|
|
:returns:
|
|
:rtype:
|
|
"""
|
|
cdrdao = Popen(CDRDAO, stderr=PIPE)
|
|
out, err = cdrdao.communicate()
|
|
if cdrdao.returncode != 1:
|
|
logger.warning("cdrdao version detection failed: "
|
|
"return code is " + str(cdrdao.returncode))
|
|
return None
|
|
m = re.compile(r'^Cdrdao version (?P<version>.*) - \(C\)').search(
|
|
err.decode('utf-8'))
|
|
if not m:
|
|
logger.warning("cdrdao version detection failed: "
|
|
"could not find version")
|
|
return None
|
|
return m.group('version')
|
|
|
|
|
|
def ReadTOCTask(device):
|
|
"""Stopgap morituri-insanity compatibility layer.
|
|
|
|
:param device: optical disk drive.
|
|
:type device:
|
|
:returns:
|
|
:rtype: TocFile
|
|
"""
|
|
return read_toc(device, fast_toc=True)
|
|
|
|
|
|
def ReadTableTask(device):
|
|
"""Stopgap morituri-insanity compatibility layer.
|
|
|
|
:param device: optical disk drive.
|
|
:type device:
|
|
:returns:
|
|
:rtype: TocFile
|
|
"""
|
|
return read_toc(device)
|
|
|
|
|
|
def getCDRDAOVersion():
|
|
"""Stopgap morituri-insanity compatibility layer.
|
|
|
|
:returns:
|
|
:rtype:
|
|
"""
|
|
return version()
|