Repository: etcd-io/bbolt (language: go)

Issue:
Open a not-exist file as read-only mode will cause create file.
If I open a database file which is not exist, bolt will return an error and create the file even if `Options.ReadOnly == true`. Why bolt still create file under read-only mode?

Here is the code:

```go
// test-open-file.go
package main

import (
    "fmt"
    "flag"
    "os"
    bolt "github.com/coreos/bbolt"
)

func check(filename string) (err error) {
    db, err := bolt.Open(filename, 0600, &bolt.Options{ReadOnly:true})
    if err != nil {
        return
    }
    defer db.Close()
    return
}

func main() {
    flag.Parse()
    args := flag.Args()
    if len(args) == 0 {
        fmt.Fprintln(os.Stderr, "Please input filename")
        os.Exit(1)
    }

    fmt.Printf("Open \"%s\"\n", args[0])
    if err := check(args[0]); err != nil {
        fmt.Fprintln(os.Stderr, err)
        os.Exit(1)
    }
    fmt.Println("ok")
}
```

Run the code:

    go run test-open-file.go a-not-exist-file.db

Under Windows, it will create two files: a-not-exist-file.db and a-not-exist-file.db.lock. The error message is:

    CreateFileMapping: Not enough storage is available to process this command.

Under Linux, it will create one file: a-not-exist-file.db. The error message is:

    write a-not-exist-file.db: bad file descriptor

The error messages above are not friendly, why not just return "file not exist"?



Discussion / hints:
Ping? Is there any option to prevent this behavior?
@m3ng9i
```go
	bolt "github.com/coreos/bbolt"
```
That doesn't seem right. Shouldn't it be
```go
	bolt "go.etcd.io/bbolt"
```

Fix patch:
diff --git a/db.go b/db.go
index 1d7cd137f..4b8a4b82d 100644
--- a/db.go
+++ b/db.go
@@ -196,6 +196,7 @@ func Open(path string, mode os.FileMode, options *Options) (*DB, error) {
 	} else {
 		// always load free pages in write mode
 		db.PreLoadFreelist = true
+		flag |= os.O_CREATE
 	}
 
 	db.openFile = options.OpenFile
@@ -205,7 +206,7 @@ func Open(path string, mode os.FileMode, options *Options) (*DB, error) {
 
 	// Open data file and separate sync handler for metadata writes.
 	var err error
-	if db.file, err = db.openFile(path, flag|os.O_CREATE, mode); err != nil {
+	if db.file, err = db.openFile(path, flag, mode); err != nil {
 		_ = db.close()
 		return nil, err
 	}


Test patch:
diff --git a/db_test.go b/db_test.go
index 153de475e..1b103676f 100644
--- a/db_test.go
+++ b/db_test.go
@@ -562,6 +562,12 @@ func TestDB_Open_ReadOnly(t *testing.T) {
 	}
 }
 
+func TestDB_Open_ReadOnly_NoCreate(t *testing.T) {
+	f := filepath.Join(t.TempDir(), "db")
+	_, err := bolt.Open(f, 0666, &bolt.Options{ReadOnly: true})
+	require.ErrorIs(t, err, os.ErrNotExist)
+}
+
 // TestOpen_BigPage checks the database uses bigger pages when
 // changing PageSize.
 func TestOpen_BigPage(t *testing.T) {