diff --git a/gramps/gen/db/generic.py b/gramps/gen/db/generic.py index 10b295240..eaea1c4b7 100644 --- a/gramps/gen/db/generic.py +++ b/gramps/gen/db/generic.py @@ -45,7 +45,8 @@ from . import (DbReadBase, DbWriteBase, DbUndo, DBLOGNAME, DBUNDOFN, KEY_TO_CLASS_MAP, REFERENCE_KEY, PERSON_KEY, FAMILY_KEY, CITATION_KEY, SOURCE_KEY, EVENT_KEY, MEDIA_KEY, PLACE_KEY, REPOSITORY_KEY, NOTE_KEY, TAG_KEY, TXNADD, TXNUPD, TXNDEL, - KEY_TO_NAME_MAP) + KEY_TO_NAME_MAP, DBMODE_R, DBMODE_W) +from .utils import write_lock_file, clear_lock_file from ..errors import HandleError from ..utils.callback import Callback from ..updatecallback import UpdateCallback @@ -581,7 +582,25 @@ class DbGeneric(DbWriteBase, DbReadBase, UpdateCallback, Callback): """ raise NotImplementedError - def load(self, directory, callback=None, mode=None, + def __check_readonly(self, name): + """ + Return True if we don't have read/write access to the database, + otherwise return False (that is, we DO have read/write access) + """ + + # See if we write to the target directory at all? + if not os.access(name, os.W_OK): + return True + + # See if we lack write access to the database file + path = os.path.join(name, 'sqlite.db') + if os.path.isfile(path) and not os.access(path, os.W_OK): + return True + + # All tests passed. Inform caller that we are NOT read only + return False + + def load(self, directory, callback=None, mode=DBMODE_W, force_schema_upgrade=False, force_bsddb_upgrade=False, force_bsddb_downgrade=False, @@ -592,6 +611,14 @@ class DbGeneric(DbWriteBase, DbReadBase, UpdateCallback, Callback): """ If update is False: then don't update any files """ + if self.__check_readonly(directory): + mode = DBMODE_R + + self.readonly = mode == DBMODE_R + + if not self.readonly: + write_lock_file(directory) + # run backend-specific code: self._initialize(directory, username, password) @@ -735,6 +762,12 @@ class DbGeneric(DbWriteBase, DbReadBase, UpdateCallback, Callback): self._set_metadata('nmap_index', self.nmap_index) self._close() + + try: + clear_lock_file(self.get_save_path()) + except IOError: + pass + self.db_is_open = False self._directory = None diff --git a/gramps/gen/db/utils.py b/gramps/gen/db/utils.py index 29a2a7c52..1fb639fba 100644 --- a/gramps/gen/db/utils.py +++ b/gramps/gen/db/utils.py @@ -39,8 +39,9 @@ import logging #------------------------------------------------------------------------ from ..plug import BasePluginManager from ..const import PLUGINS_DIR, USER_PLUGINS +from ..constfunc import win, get_env_var from ..config import config -from .dbconst import DBLOGNAME +from .dbconst import DBLOGNAME, DBLOCKFN #------------------------------------------------------------------------- # @@ -179,3 +180,35 @@ def __index_surname(surn_list): else: surn = "" return surn + +def clear_lock_file(name): + try: + os.unlink(os.path.join(name, DBLOCKFN)) + except OSError: + return + +def write_lock_file(name): + if not os.path.isdir(name): + os.mkdir(name) + with open(os.path.join(name, DBLOCKFN), "w", encoding='utf8') as f: + if win(): + user = get_env_var('USERNAME') + host = get_env_var('USERDOMAIN') + if host is None: + host = "" + else: + host = os.uname()[1] + # An ugly workaround for os.getlogin() issue with Konsole + try: + user = os.getlogin() + except: + # not win, so don't need get_env_var. + # under cron getlogin() throws and there is no USER. + user = os.environ.get('USER', 'noUSER') + if host: + text = "%s@%s" % (user, host) + else: + text = user + # Save only the username and host, so the massage can be + # printed with correct locale in DbManager.py when a lock is found + f.write(text) diff --git a/gramps/plugins/db/bsddb/write.py b/gramps/plugins/db/bsddb/write.py index 358055e13..668948e82 100644 --- a/gramps/plugins/db/bsddb/write.py +++ b/gramps/plugins/db/bsddb/write.py @@ -72,11 +72,11 @@ from . import (DbBsddbRead, DbWriteBase, BSDDBTxn, from gramps.gen.db import exceptions from gramps.gen.db.dbconst import * +from gramps.gen.db.utils import write_lock_file, clear_lock_file from gramps.gen.utils.callback import Callback from gramps.gen.utils.id import create_id from gramps.gen.updatecallback import UpdateCallback from gramps.gen.errors import DbError, HandleError -from gramps.gen.constfunc import win, get_env_var from gramps.gen.const import HOME_DIR, GRAMPS_LOCALE as glocale _ = glocale.translation.gettext @@ -2308,38 +2308,6 @@ class DbBsddb(DbBsddbRead, DbWriteBase, UpdateCallback): def _mkname(path, name): return os.path.join(path, name + DBEXT) -def clear_lock_file(name): - try: - os.unlink(os.path.join(name, DBLOCKFN)) - except OSError: - return - -def write_lock_file(name): - if not os.path.isdir(name): - os.mkdir(name) - with open(os.path.join(name, DBLOCKFN), "w", encoding='utf8') as f: - if win(): - user = get_env_var('USERNAME') - host = get_env_var('USERDOMAIN') - if host is None: - host = "" - else: - host = os.uname()[1] - # An ugly workaround for os.getlogin() issue with Konsole - try: - user = os.getlogin() - except: - # not win, so don't need get_env_var. - # under cron getlogin() throws and there is no USER. - user = os.environ.get('USER', 'noUSER') - if host: - text = "%s@%s" % (user, host) - else: - text = user - # Save only the username and host, so the massage can be - # printed with correct locale in DbManager.py when a lock is found - f.write(text) - def upgrade_researcher(owner_data): """ Upgrade researcher data to include a locality field in the address.