diff --git a/src/calibre/constants.py b/src/calibre/constants.py index b731d37d59..c557256d25 100644 --- a/src/calibre/constants.py +++ b/src/calibre/constants.py @@ -1,6 +1,7 @@ #!/usr/bin/env python # License: GPLv3 Copyright: 2015, Kovid Goyal from polyglot.builtins import environ_item, hasenv +from functools import lru_cache import sys, locale, codecs, os, collections, collections.abc __appname__ = 'calibre' @@ -445,3 +446,16 @@ def get_windows_number_formats(): def trash_name(): return _('Trash') if ismacos else _('Recycle Bin') + + +@lru_cache(maxsize=2) +def get_umask(): + mask = os.umask(0o666) + os.umask(mask) + return mask + + +# call this at startup as it changed process global state, which doesnt work +# with multi-threading. It's absurd there is no way to safely read the current +# umask of a process. +get_umask() diff --git a/src/calibre/utils/config_base.py b/src/calibre/utils/config_base.py index 9913a6a328..880aa7f854 100644 --- a/src/calibre/utils/config_base.py +++ b/src/calibre/utils/config_base.py @@ -4,13 +4,19 @@ __license__ = 'GPL v3' __copyright__ = '2011, Kovid Goyal ' __docformat__ = 'restructuredtext en' -import os, re, traceback, numbers -from contextlib import suppress -from functools import partial +import numbers +import os +import re +import traceback from collections import defaultdict +from contextlib import suppress from copy import deepcopy +from functools import partial -from calibre.constants import config_dir, CONFIG_DIR_MODE, preferred_encoding, filesystem_encoding, iswindows +from calibre.constants import ( + CONFIG_DIR_MODE, config_dir, filesystem_encoding, get_umask, iswindows, + preferred_encoding +) from polyglot.builtins import iteritems plugin_dir = os.path.join(config_dir, 'plugins') @@ -376,6 +382,8 @@ def commit_data(file_path, data): os.makedirs(bdir, exist_ok=True, mode=CONFIG_DIR_MODE) try: with tempfile.NamedTemporaryFile(dir=bdir, prefix=os.path.basename(file_path).split('.')[0] + '-atomic-', delete=False) as f: + if hasattr(os, 'fchmod'): + os.fchmod(f.fileno(), 0o666 & ~get_umask()) f.write(data) retry_on_fail(os.replace, f.name, file_path) finally: