Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use Django default file mode-settings for uploaded files, and limit use of system() #64

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion binary_database_files/storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ def _open(self, name, mode="rb"):
fqfn = self.path(name)
if os.path.isfile(fqfn):
# print('Loading file into database.')
self._save(name, open(fqfn, mode))
with open(fqfn, mode) as fd:
self._save(name, fd)
fh = super(DatabaseStorage, self)._open(name, mode)
content = fh.read()
size = fh.size
Expand Down
63 changes: 50 additions & 13 deletions binary_database_files/utils.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import hashlib
import logging
import os
import shutil

from django.conf import settings

from binary_database_files import settings as _settings

logger = logging.getLogger(__name__)


def is_fresh(name, content_hash):
"""
Expand Down Expand Up @@ -41,14 +45,38 @@ def get_hash_fn(name):
fqfn = os.path.join(settings.MEDIA_ROOT, name)
fqfn = os.path.normpath(fqfn)
fqfn_parts = os.path.split(fqfn)
if not os.path.isdir(fqfn_parts[0]):
os.makedirs(fqfn_parts[0])

create_directory_for_file(fqfn)

hash_fn = os.path.join(
fqfn_parts[0], _settings.DB_FILES_DEFAULT_HASH_FN_TEMPLATE % fqfn_parts[1]
)
return hash_fn


def create_directory_for_file(full_path):

directory = os.path.dirname(full_path)
directory_permissions_mode = settings.FILE_UPLOAD_DIRECTORY_PERMISSIONS

if os.path.isdir(directory):
return

try:
if directory_permissions_mode is not None:
# Set the umask because os.makedirs() doesn't apply the "mode"
# argument to intermediate-level directories.
old_umask = os.umask(0o777 & ~directory_permissions_mode)
try:
os.makedirs(directory, directory_permissions_mode, exist_ok=True)
finally:
os.umask(old_umask)
else:
os.makedirs(directory, exist_ok=True)
except FileExistsError:
raise FileExistsError('%s exists and is not a directory.' % directory)


def write_file(name, content, overwrite=False):
"""
Writes the given content to the relative filename under the MEDIA_ROOT.
Expand All @@ -57,10 +85,11 @@ def write_file(name, content, overwrite=False):
fqfn = os.path.normpath(fqfn)
if os.path.isfile(fqfn) and not overwrite:
return
fqfn_parts = os.path.split(fqfn)
if not os.path.isdir(fqfn_parts[0]):
os.makedirs(fqfn_parts[0])
open(fqfn, "wb").write(content)

create_directory_for_file(fqfn)

with open(fqfn, "wb") as fd:
fd.write(content)

# Cache hash.
hash_value = get_file_hash(fqfn)
Expand All @@ -69,20 +98,28 @@ def write_file(name, content, overwrite=False):
value = bytes(hash_value, "utf-8")
except TypeError:
value = hash_value
open(hash_fn, "wb").write(value)

with open(hash_fn, "wb") as fd:
fd.write(value)

# Set ownership and permissions.
uname = getattr(settings, "DATABASE_FILES_USER", None)
gname = getattr(settings, "DATABASE_FILES_GROUP", None)
if gname:
gname = ":" + gname
if uname:
os.system('chown -RL %s%s "%s"' % (uname, gname, fqfn_parts[0])) # noqa: S605
if uname is not None or gname is not None:
try:
shutil.chown(fqfn, user=uname, group=gname)
shutil.chown(hash_fn, user=uname, group=gname)
except OSError as e:
logger.warning('Could not chown file %s: %s', fqfn, e)

# Set permissions.
perms = getattr(settings, "DATABASE_FILES_PERMS", None)
perms = getattr(settings, "DATABASE_FILES_PERMS", settings.FILE_UPLOAD_PERMISSIONS)
if perms:
os.system('chmod -R %s "%s"' % (perms, fqfn_parts[0])) # noqa: S605
try:
os.chmod(fqfn, perms)
os.chmod(hash_fn, perms)
except OSError as e:
logger.warning('Could not chmod file %s: %s', fqfn, e)


def get_file_hash(fin, force_encoding=None, encoding=None, errors=None, chunk_size=128):
Expand Down