Ensure specified destination is writable before starting pipeline process

This commit is contained in:
James R. Barlow
2017-01-26 22:08:24 -08:00
parent 55aeaec293
commit 9a15a4db10
4 changed files with 40 additions and 9 deletions
+5 -1
View File
@@ -26,7 +26,7 @@ import ruffus.proxy_logger as proxy_logger
from .pipeline import JobContext, JobContextManager, re_symlink, \
cleanup_working_files, build_pipeline
from .pdfa import file_claims_pdfa
from .helpers import is_iterable_notstr, re_symlink
from .helpers import is_iterable_notstr, re_symlink, is_file_writable
from .exec import tesseract, qpdf
from . import PROGRAM_NAME, VERSION
@@ -518,6 +518,10 @@ def run_pipeline():
is connected to a terminal. Please redirect stdout to a
file."""))
return ExitCode.bad_args
elif not is_file_writable(options.output_file):
_log.error(textwrap.dedent("""\
Cutput file location is not writable."""))
return ExitCode.file_access_error
manager = JobContextManager()
manager.register('JobContext', JobContext)
+24
View File
@@ -3,6 +3,7 @@
from functools import partial
from collections.abc import Iterable
from contextlib import suppress
import sys
import os
@@ -53,3 +54,26 @@ def is_iterable_notstr(thing):
def page_number(input_file):
return int(os.path.basename(input_file)[0:6])
def is_file_writable(test_file):
"""Intentionally racy test if target is writable.
We intend to write to the output file if and only if we succeed and
can replace it atomically. Before doing the OCR work, make sure
the location is writable.
"""
if os.path.exists(test_file):
return os.access(
test_file, os.W_OK,
effective_ids=(os.access in os.supports_effective_ids))
else:
try:
fp = open(test_file, 'wb')
except OSError as e:
return False
else:
fp.close()
with suppress(OSError):
os.unlink(test_file)
return True
+10
View File
@@ -680,3 +680,13 @@ def test_very_high_dpi(spoof_tesseract_cache, resources, outpdf):
def test_overlay(spoof_tesseract_noop, resources, outpdf):
check_ocrmypdf(resources / 'overlay.pdf', outpdf,
env=spoof_tesseract_noop)
def test_destination_not_writable(spoof_tesseract_noop, resources, outdir):
protected_file = outdir / 'protected.pdf'
protected_file.touch()
protected_file.chmod(0o400) # Read-only
p, out, err = run_ocrmypdf(
resources / 'jbig2.pdf', protected_file,
env=spoof_tesseract_noop)
assert p.returncode == ExitCode.file_access_error, "Expected error"
+1 -8
View File
@@ -15,20 +15,13 @@ from ocrmypdf.pdfa import file_claims_pdfa
from ocrmypdf.exec import tesseract
TESTS_ROOT = os.path.abspath(os.path.dirname(__file__))
SPOOF_PATH = os.path.join(TESTS_ROOT, 'spoof')
PROJECT_ROOT = os.path.dirname(TESTS_ROOT)
TEST_RESOURCES = os.path.join(PROJECT_ROOT, 'tests', 'resources')
OCRMYPDF = [sys.executable, '-m', 'ocrmypdf']
# Skip all tests in this file if not tesseract 4
pytestmark = pytest.mark.skipif(not tesseract.v4(),
reason="tesseract 4.0 required")
@pytest.mark.skipif(not tesseract.has_textonly_pdf(),
reason="requires textonly_pdf parameter")
reason="requires textonly_pdf feature")
def test_textonly_pdf(resources, outdir):
pytest.helpers.check_ocrmypdf(
resources / 'linn.pdf',