wip unlocking locked db

This commit is contained in:
Chakib Ben Ziane 2018-12-04 18:06:30 +01:00
parent bd5b8ee815
commit 1f6db4c4aa
7 changed files with 197 additions and 49 deletions

View File

@ -217,17 +217,6 @@ func New(name string, dbPath string, dbFormat string, opts ...DsnOptions) *DB {
}
//TODO: try unlock at the browser level !
func (db *DB) tryUnlock() error {
log.Debug("Unlocking ...")
// Find if multiProcessAccess option is defined
//TODO:
//if v, err := mozilla.HasPref(path ???)
//
return nil
}
//TODO: Should check if DB is locked
// We should export Open() in its own method and wrap
// with interface so we can mock it and test the lock status in Init()
@ -253,7 +242,7 @@ func (db *DB) Init() (*DB, error) {
}
if locked {
return nil, DBErr(db.Name, ErrVfsLocked)
return nil, ErrVfsLocked
}
}
@ -265,7 +254,7 @@ func (db *DB) Init() (*DB, error) {
// Secondary lock check provided by sqlx Ping() method
if err != nil && sqlErr.Code == sqlite3.ErrBusy {
return nil, DBError{DBName: db.Name, Err: err}
return nil, ErrVfsLocked
}

View File

@ -119,7 +119,7 @@ func TestInitLocked(t *testing.T) {
t.Fail()
}
if err != DBErr(testDB.Name, ErrVfsLocked) {
if err != ErrVfsLocked {
t.Fail()
}
@ -142,9 +142,7 @@ func TestInitLocked(t *testing.T) {
t.Fail()
}
e, _ := err.(DBError).Err.(sqlite3.Error)
if e.Code != sqlite3.ErrBusy {
if err != ErrVfsLocked {
t.Fail()
}

View File

@ -5,6 +5,7 @@ package main
import (
"database/sql"
"gomark/database"
"gomark/mozilla"
"gomark/parsing"
"gomark/tree"
"gomark/utils"
@ -52,7 +53,7 @@ const (
var Firefox = BrowserPaths{
BookmarkFile: "places.sqlite",
BookmarkDir: "/home/spike/.mozilla/firefox/p1rrgord.default/",
BookmarkDir: "/home/spike/.mozilla/firefox/7otsk3vs.test_bookmarks",
}
const (
@ -116,6 +117,9 @@ func FFPlacesUpdateHook(op int, db string, table string, rowid int64) {
fflog.Debug(op)
}
//TODO: Test browser creation errors
// In case of critical errors degrade the browser to only log errors and disable
// all directives
func NewFFBrowser() IBrowser {
var err error
@ -142,7 +146,15 @@ func NewFFBrowser() IBrowser {
if err != nil {
//Check Lock Error
log.Fatal(err)
if err == database.ErrVfsLocked {
// Try to unlock db
e := mozilla.UnlockPlaces(browser.baseDir)
if e != nil {
log.Panic(e)
}
} else {
log.Panic(err)
}
}
// Buffer that lives accross Run() jobs

View File

@ -1,5 +1,11 @@
package mozilla
import (
"errors"
"gomark/logging"
"path"
)
const (
// This option disables the VFS lock on firefox
// Sqlite allows file locking of the database using the local file system VFS.
@ -21,4 +27,50 @@ var (
PlacesDSN = map[string]string{
"_jouranl_mode": "WAL",
}
log = logging.GetLogger("MOZ")
)
var (
ErrMultiProcessAlreadyEnabled = errors.New("multiProcessAccess already enabled")
)
//TODO: try unlock at the browser level !
// Try to unlock vfs locked places.sqlite by setting the `PrefMultiProcessAccess`
// property in prefs.js
func UnlockPlaces(dir string) error {
log.Debug("Unlocking ...")
prefsPath := path.Join(dir, PrefsFile)
// Find if multiProcessAccess option is defined
pref, err := GetPrefBool(prefsPath, PrefMultiProcessAccess)
if err != nil && err != ErrPrefNotFound {
return err
}
// If pref already defined and true raise an error
if pref {
log.Criticalf("pref <%s> already defined as <%s>",
PrefMultiProcessAccess, pref)
return ErrMultiProcessAlreadyEnabled
// Set the preference
} else {
log.Debug("pref not defined")
// enable multi process access in firefox
err = SetPrefBool(prefsPath,
PrefMultiProcessAccess,
true)
if err != nil {
return err
}
}
return nil
}

View File

@ -13,7 +13,12 @@ const (
// Parses vales in prefs.js under the form:
// user_pref("my.pref.option", value);
REFirefoxPrefs = `user_pref\("(?P<option>%s)",\s+"*(?P<value>.*[^"])"*\);`
REFirefoxPrefs = `user_pref\("(?P<option>%s)",\s+"*(?P<value>.*[^"])"*\)\s*;\s*(\n|$)`
)
var (
ErrPrefNotFound = errors.New("pref not defined")
ErrPrefNotBool = errors.New("pref is not bool")
)
// Finds and returns a prefernce definition.
@ -39,6 +44,7 @@ func FindPref(path string, name string) (string, error) {
return results["value"], nil
}
// Returns true if the `name` preference is found in `prefs.js`
func HasPref(path string, name string) (bool, error) {
res, err := FindPref(path, name)
if err != nil {
@ -62,7 +68,7 @@ func GetPrefBool(path string, name string) (bool, error) {
}
if val == "" {
return false, errors.New("not found")
return false, ErrPrefNotFound
}
if val == "true" {
@ -71,7 +77,7 @@ func GetPrefBool(path string, name string) (bool, error) {
return false, nil
}
return false, errors.New("not a bool")
return false, ErrPrefNotBool
}
@ -84,18 +90,43 @@ func SetPrefBool(path string, name string, val bool) error {
}
mode := info.Mode()
f, err := os.OpenFile(path, os.O_RDWR|os.O_APPEND, mode)
defer f.Close()
// Pref already defined, replace it
if v, _ := HasPref(path, name); v {
if err != nil {
return err
}
f, err := os.OpenFile(path, os.O_RDWR, mode)
defer f.Sync()
defer f.Close()
fmt.Println(name, val)
fmt.Fprintf(f, "user_pref(\"%s\", %t);\n", name, val)
err = f.Sync()
if err != nil {
return err
if err != nil {
return err
}
re := regexp.MustCompile(fmt.Sprintf(REFirefoxPrefs, name))
template := []byte(fmt.Sprintf("user_pref(\"$option\", %t) ;\n", val))
text, err := ioutil.ReadAll(f)
if err != nil {
return err
}
_, err = f.Seek(0, 0)
if err != nil {
return err
}
output := string(re.ReplaceAll(text, template))
fmt.Fprint(f, output)
} else {
f, err := os.OpenFile(path, os.O_RDWR|os.O_APPEND, mode)
defer f.Sync()
defer f.Close()
if err != nil {
return err
}
// Append pref
fmt.Fprintf(f, "user_pref(\"%s\", %t);\n", name, val)
}
return nil

View File

@ -1,10 +1,12 @@
package mozilla
import (
"bufio"
"fmt"
"io/ioutil"
"os"
"testing"
"time"
)
const (
@ -91,6 +93,9 @@ func resetTestPrefFile(f *os.File) {
if err != nil {
panic(err)
}
f.Seek(0, 0)
f.Sync()
}
func TestFindPref(t *testing.T) {
@ -137,35 +142,94 @@ func TestGetPrefBool(t *testing.T) {
_, err := GetPrefBool(prefsTempFile.Name(), TestPrefs["STRING"].name)
if err != nil &&
err.Error() != "not a bool" {
err != ErrPrefNotBool {
t.Error(err)
}
})
// Should return false for undefined pref
t.Run("NOTDEFINED", func(t *testing.T) {
val, err := GetPrefBool(prefsTempFile.Name(), "not.exists.bool")
if err != nil && err != ErrPrefNotFound {
t.Error(err)
}
if val != false {
t.Fail()
}
})
}
func TestSetPrefBool(t *testing.T) {
resetTestPrefFile(prefsTempFile)
// Write some data to test the append behavior
writeTestPrefFile(prefsTempFile, TestPrefs["STRING"])
t.Run("APPEND", func(t *testing.T) {
setVal, _ := TestPrefs["TRUE"].value.(bool)
resetTestPrefFile(prefsTempFile)
err := SetPrefBool(prefsTempFile.Name(), TestPrefs["TRUE"].name, setVal)
// Write some data to test the append behavior
writeTestPrefFile(prefsTempFile, TestPrefs["STRING"])
if err != nil {
t.Error(err)
}
setVal, _ := TestPrefs["TRUE"].value.(bool)
res, err := GetPrefBool(prefsTempFile.Name(), TestPrefs["TRUE"].name)
if err != nil {
t.Error(err)
}
err := SetPrefBool(prefsTempFile.Name(), TestPrefs["TRUE"].name, setVal)
if res != setVal {
t.Fail()
}
if err != nil {
t.Error(err)
}
res, err := GetPrefBool(prefsTempFile.Name(), TestPrefs["TRUE"].name)
if err != nil {
t.Error(err)
}
if res != setVal {
t.Fail()
}
})
t.Run("REPLACE", func(t *testing.T) {
resetTestPrefFile(prefsTempFile)
scanner := bufio.NewScanner(prefsTempFile)
writeTestPrefFile(prefsTempFile, TestPrefs["STRING"])
writeTestPrefFile(prefsTempFile, TestPrefs["FALSE"])
prefsTempFile.Seek(0, 0)
// Check if line was replaces
var lines int
for scanner.Scan() {
lines++
}
err := SetPrefBool(prefsTempFile.Name(), TestPrefs["FALSE"].name, true)
if err != nil {
t.Error(err)
}
prefsTempFile.Seek(0, 0)
scanner = bufio.NewScanner(prefsTempFile)
// Check if line was replaces
for lines = 0; scanner.Scan(); {
lines++
}
if lines != 2 {
t.Error("SetPrefBool should replace existing Pref")
}
res, err := GetPrefBool(prefsTempFile.Name(), TestPrefs["FALSE"].name)
if err != nil {
t.Error(err)
}
if !res {
t.Fail()
}
time.Sleep(4 * time.Second)
})
}
func TestHasPref(t *testing.T) {

View File

@ -18,8 +18,10 @@ func FileProcessUsers(path string) ([]*psutil.Process, error) {
for _, p := range processes {
files, err := p.OpenFiles()
errPath, _ := err.(*os.PathError)
if err != nil &&
err != os.ErrPermission {
errPath.Err.Error() != os.ErrPermission.Error() {
log.Error(err)
return nil, err
}