maildir,notmuch: avoid leaking open files

Previously, Message.NewReader returned the wrapped buffered reader
without a reference to the opened file, so the files descriptors
were left unclosed after reading.  Now, the file reader is returned
directly and closed on the call site.  Buffering is not needed here
because it is an implementation detail of go-message.

Fixes: https://todo.sr.ht/~rjarry/aerc/9
This commit is contained in:
Nguyễn Gia Phong 2022-01-20 01:10:08 +07:00 committed by Robin Jarry
parent beae17a6da
commit 904ffacb0e
7 changed files with 16 additions and 28 deletions

View file

@ -211,7 +211,7 @@ func parseAddressList(h *mail.Header, key string) ([]*mail.Address, error) {
// RawMessage is an interface that describes a raw message
type RawMessage interface {
NewReader() (io.Reader, error)
NewReader() (io.ReadCloser, error)
ModelFlags() ([]models.Flag, error)
Labels() ([]string, error)
UID() uint32
@ -225,6 +225,7 @@ func MessageInfo(raw RawMessage) (*models.MessageInfo, error) {
if err != nil {
return nil, err
}
defer r.Close()
msg, err := message.Read(r)
if err != nil {
return nil, fmt.Errorf("could not read message: %v", err)

View file

@ -1,9 +1,9 @@
package lib
import (
"bytes"
"io"
"io/ioutil"
"os"
"path/filepath"
"testing"
@ -36,23 +36,17 @@ func TestMessageInfoHandledError(t *testing.T) {
}
type mockRawMessage struct {
body []byte
}
func newMockRawMessage(body []byte) *mockRawMessage {
return &mockRawMessage{
body: body,
}
path string
}
func newMockRawMessageFromPath(p string) *mockRawMessage {
b, err := ioutil.ReadFile(p)
die(err)
return newMockRawMessage(b)
return &mockRawMessage{
path: p,
}
}
func (m *mockRawMessage) NewReader() (io.Reader, error) {
return bytes.NewReader(m.body), nil
func (m *mockRawMessage) NewReader() (io.ReadCloser, error) {
return os.Open(m.path)
}
func (m *mockRawMessage) ModelFlags() ([]models.Flag, error) { return nil, nil }
func (m *mockRawMessage) Labels() ([]string, error) { return nil, nil }

View file

@ -1,7 +1,6 @@
package maildir
import (
"bufio"
"fmt"
"io"
@ -20,12 +19,8 @@ type Message struct {
}
// NewReader reads a message into memory and returns an io.Reader for it.
func (m Message) NewReader() (io.Reader, error) {
f, err := m.dir.Open(m.key)
if err != nil {
return nil, err
}
return bufio.NewReader(f), nil
func (m Message) NewReader() (io.ReadCloser, error) {
return m.dir.Open(m.key)
}
// Flags fetches the set of flags currently applied to the message.

View file

@ -159,6 +159,7 @@ func (w *Worker) searchKey(key uint32, criteria *searchCriteria,
if err != nil {
return false, err
}
defer reader.Close()
bytes, err := ioutil.ReadAll(reader)
if err != nil {
return false, err

View file

@ -432,6 +432,7 @@ func (w *Worker) handleFetchFullMessages(msg *types.FetchFullMessages) error {
w.worker.Logger.Printf("could not get message reader: %v", err)
return err
}
defer r.Close()
w.worker.PostMessage(&types.FullMessage{
Message: types.RespondTo(msg),
Content: &models.FullMessage{

View file

@ -4,7 +4,6 @@
package notmuch
import (
"bufio"
"fmt"
"io"
"os"
@ -23,16 +22,12 @@ type Message struct {
}
// NewReader returns a reader for a message
func (m *Message) NewReader() (io.Reader, error) {
func (m *Message) NewReader() (io.ReadCloser, error) {
name, err := m.Filename()
if err != nil {
return nil, err
}
f, err := os.Open(name)
if err != nil {
return nil, err
}
return bufio.NewReader(f), nil
return os.Open(name)
}
// MessageInfo populates a models.MessageInfo struct for the message.

View file

@ -367,6 +367,7 @@ func (w *worker) handleFetchFullMessages(msg *types.FetchFullMessages) error {
w.w.Logger.Printf("could not get message reader: %v", err)
return err
}
defer r.Close()
w.w.PostMessage(&types.FullMessage{
Message: types.RespondTo(msg),
Content: &models.FullMessage{