diff --git a/core/main_db.py b/core/main_db.py index d9d7c1b9..2397607f 100644 --- a/core/main_db.py +++ b/core/main_db.py @@ -7,14 +7,17 @@ from __future__ import ( unicode_literals, ) +import os.path import re import sqlite3 +import sys import time from six import text_type, PY2 import core from core import logger +from core import permissions if PY2: class Row(sqlite3.Row, object): @@ -60,10 +63,29 @@ def db_filename(filename='nzbtomedia.db', suffix=None): class DBConnection(object): def __init__(self, filename='nzbtomedia.db', suffix=None, row_type=None): - self.filename = filename - self.connection = sqlite3.connect(db_filename(filename), 20) - self.connection.row_factory = Row + path = db_filename(filename) + try: + self.connection = sqlite3.connect(path, 20) + except sqlite3.OperationalError as error: + if os.path.exists(path): + logger.error('Please check permissions on database: {0}'.format(path)) + else: + logger.error('Database file does not exist') + logger.error('Please check permissions on directory: {0}'.format(path)) + path = os.path.dirname(path) + mode = permissions.mode(path) + owner, group = permissions.ownership(path) + logger.error( + "=== PERMISSIONS ===========================\n" + " Path : {0}\n" + " Mode : {1}\n" + " Owner: {2}\n" + " Group: {3}\n" + "===========================================".format(path, mode[-3:], owner, group), + ) + else: + self.connection.row_factory = Row def check_db_version(self): result = None @@ -256,7 +278,11 @@ class DBSanityCheck(object): def upgrade_database(connection, schema): logger.log(u'Checking database structure...', logger.MESSAGE) - _process_upgrade(connection, schema) + try: + _process_upgrade(connection, schema) + except Exception as error: + logger.error(error) + sys.exit(1) def pretty_name(class_name): diff --git a/core/permissions.py b/core/permissions.py new file mode 100644 index 00000000..39789672 --- /dev/null +++ b/core/permissions.py @@ -0,0 +1,64 @@ +import os +import sys +import logging + +log = logging.getLogger(__name__) +log.addHandler(logging.NullHandler()) + +WINDOWS = sys.platform == 'win32' +POSIX = not WINDOWS + +try: + import pwd + import grp +except ImportError: + if POSIX: + raise + +try: + from win32security import GetNamedSecurityInfo + from win32security import LookupAccountSid + from win32security import GROUP_SECURITY_INFORMATION + from win32security import OWNER_SECURITY_INFORMATION + from win32security import SE_FILE_OBJECT +except ImportError: + if WINDOWS: + raise + + +def mode(path): + """Get permissions.""" + return oct(os.stat(path).st_mode & 0o777) + + +def nt_ownership(path): + """Get the owner and group for a file or directory.""" + def fully_qualified_name(sid): + """Return a fully qualified account name.""" + name, domain, _acct_type = LookupAccountSid(None, sid) + return '{}\\{}'.format(domain, name) + + security_descriptor = GetNamedSecurityInfo( + os.fspath(path), + SE_FILE_OBJECT, + OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION, + ) + owner_sid = security_descriptor.GetSecurityDescriptorOwner() + group_sid = security_descriptor.GetSecurityDescriptorGroup() + owner = fully_qualified_name(owner_sid) + group = fully_qualified_name(group_sid) + return owner, group + + +def posix_ownership(path): + """Get the owner and group for a file or directory.""" + stat_result = os.stat(path) + owner = pwd.getpwuid(stat_result.st_uid) + group = grp.getgrgid(stat_result.st_gid) + return owner, group + + +if WINDOWS: + ownership = nt_ownership +else: + ownership = posix_ownership