wip unlocking locked db
This commit is contained in:
parent
bd5b8ee815
commit
1f6db4c4aa
@ -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
|
||||
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
}
|
||||
|
||||
|
16
firefox.go
16
firefox.go
@ -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
|
||||
|
@ -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
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user