1
0
mirror of https://github.com/certbot/certbot.git synced 2026-01-21 19:01:07 +03:00
Files
certbot/letsencrypt/le_util.py
2015-05-16 21:27:06 -07:00

120 lines
3.5 KiB
Python

"""Utilities for all Let's Encrypt."""
import collections
import errno
import os
import stat
from letsencrypt import errors
Key = collections.namedtuple("Key", "file pem")
# Note: form is the type of data, "pem" or "der"
CSR = collections.namedtuple("CSR", "file data form")
def make_or_verify_dir(directory, mode=0o755, uid=0):
"""Make sure directory exists with proper permissions.
:param str directory: Path to a directory.
:param int mode: Directory mode.
:param int uid: Directory owner.
:raises LetsEncryptClientError: if a directory already exists,
but has wrong permissions or owner
:raises OSError: if invalid or inaccessible file names and
paths, or other arguments that have the correct type,
but are not accepted by the operating system.
"""
try:
os.makedirs(directory, mode)
except OSError as exception:
if exception.errno == errno.EEXIST:
if not check_permissions(directory, mode, uid):
raise errors.LetsEncryptClientError(
"%s exists, but does not have the proper "
"permissions or owner" % directory)
else:
raise
def check_permissions(filepath, mode, uid=0):
"""Check file or directory permissions.
:param str filepath: Path to the tested file (or directory).
:param int mode: Expected file mode.
:param int uid: Expected file owner.
:returns: True if `mode` and `uid` match, False otherwise.
:rtype: bool
"""
file_stat = os.stat(filepath)
return stat.S_IMODE(file_stat.st_mode) == mode and file_stat.st_uid == uid
def unique_file(path, mode=0o777):
"""Safely finds a unique file for writing only (by default).
:param str path: path/filename.ext
:param int mode: File mode
:returns: tuple of file object and file name
"""
path, tail = os.path.split(path)
count = 0
while True:
fname = os.path.join(path, "%04d_%s" % (count, tail))
try:
file_d = os.open(fname, os.O_CREAT | os.O_EXCL | os.O_RDWR, mode)
return os.fdopen(file_d, "w"), fname
except OSError:
pass
count += 1
def unique_lineage_name(path, filename, mode=0o777):
"""Safely finds a unique file for writing only (by default). Uses a
file lineage convention.
:param str path: directory path
:param str filename: proposed filename
:param int mode: file mode
:returns: tuple of file object and file name (which may be modified from
the requested one by appending digits to ensure uniqueness)
:raises OSError: if writing files fails for an unanticipated reason,
such as a full disk or a lack of permission to write to specified
location.
"""
fname = os.path.join(path, "%s.conf" % (filename))
try:
file_d = os.open(fname, os.O_CREAT | os.O_EXCL | os.O_RDWR, mode)
return os.fdopen(file_d, "w"), fname
except OSError as err:
if err.errno != errno.EEXIST:
raise err
count = 1
while True:
fname = os.path.join(path, "%s-%04d.conf" % (filename, count))
try:
file_d = os.open(fname, os.O_CREAT | os.O_EXCL | os.O_RDWR, mode)
return os.fdopen(file_d, "w"), fname
except OSError as err:
if err.errno != errno.EEXIST:
raise err
count += 1
def safely_remove(path):
"""Remove a file that may not exist."""
try:
os.remove(path)
except OSError as err:
if err.errno != errno.ENOENT:
raise