~sircmpwn/aerc

This thread contains a patchset. You're looking at the original emails, but you may wish to use the patch review UI. Review patch
2 2

[PATCH v2] maildir: Provide nicer error message on invalid url

Details
Message ID
<20200724193850.40654-1-tero.koskinen@iki.fi>
DKIM signature
missing
Download raw message
Patch: +31 -4
If accounts.conf contains an invalid maildir url, return a nice
error instead of panicking.

Log a couple of different error cases to provide extra
information about the error to the user.
---
 worker/maildir/container.go | 18 +++++++++++++++---
 worker/maildir/worker.go    | 17 ++++++++++++++++-
 2 files changed, 31 insertions(+), 4 deletions(-)

diff --git a/worker/maildir/container.go b/worker/maildir/container.go
index cd9a447..fd46fd8 100644
--- a/worker/maildir/container.go
+++ b/worker/maildir/container.go
@@ -21,15 +21,27 @@ type Container struct {
}

// NewContainer creates a new container at the specified directory
// TODO: return an error if the provided directory is not accessible
func NewContainer(dir string, l *log.Logger) *Container {
	return &Container{dir: dir, uids: uidstore.NewStore(), log: l}
func NewContainer(dir string, l *log.Logger) (*Container, error) {
	f, err := os.Open(dir)
	if err != nil {
		return nil, err
	}
	s, _ := f.Stat()
	f.Close()
	if !s.IsDir() {
		return nil, fmt.Errorf("Given maildir '%s' not a directory", dir)
	}
	return &Container{dir: dir, uids: uidstore.NewStore(), log: l}, nil
}

// ListFolders returns a list of maildir folders in the container
func (c *Container) ListFolders() ([]string, error) {
	folders := []string{}
	err := filepath.Walk(c.dir, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return fmt.Errorf("Invalid path '%s': error: %v", path, err)

		}
		if !info.IsDir() {
			return nil
		}
diff --git a/worker/maildir/worker.go b/worker/maildir/worker.go
index ce548ff..d1ff3c2 100644
--- a/worker/maildir/worker.go
+++ b/worker/maildir/worker.go
@@ -1,6 +1,7 @@
package maildir

import (
	"errors"
	"fmt"
	"io"
	"net/url"
@@ -221,7 +222,15 @@ func (w *Worker) handleConfigure(msg *types.Configure) error {
		}
		dir = filepath.Join(home, u.Path)
	}
	w.c = NewContainer(dir, w.worker.Logger)
	if len(dir) == 0 {
		return fmt.Errorf("could not resolve maildir from URL '%s'", msg.Config.Source)
	}
	c, err := NewContainer(dir, w.worker.Logger)
	if err != nil {
		w.worker.Logger.Printf("could not configure maildir: %s", dir)
		return err
	}
	w.c = c
	w.worker.Logger.Printf("configured base maildir: %s", dir)
	return nil
}
@@ -231,6 +240,12 @@ func (w *Worker) handleConnect(msg *types.Connect) error {
}

func (w *Worker) handleListDirectories(msg *types.ListDirectories) error {
	// TODO If handleConfigure has returned error, w.c is nil.
	// It could be better if we skip directory listing completely
	// when configure fails.
	if w.c == nil {
		return errors.New("Incorrect maildir directory")
	}
	dirs, err := w.c.ListFolders()
	if err != nil {
		w.worker.Logger.Printf("error listing directories: %v", err)
-- 
2.27.0
Details
Message ID
<20200725062316.wytua7hzqrydwd7k@feather.localdomain>
In-Reply-To
<20200724193850.40654-1-tero.koskinen@iki.fi> (view parent)
DKIM signature
missing
Download raw message
Hi,
Thanks for the update

On Fri, Jul 24, 2020 at 10:38:50PM +0300, Tero Koskinen wrote:
> diff --git a/worker/maildir/container.go b/worker/maildir/container.go
> index cd9a447..fd46fd8 100644
> --- a/worker/maildir/container.go
> +++ b/worker/maildir/container.go
> @@ -21,15 +21,27 @@ type Container struct {
>  }
>  
>  // NewContainer creates a new container at the specified directory
> -// TODO: return an error if the provided directory is not accessible
> -func NewContainer(dir string, l *log.Logger) *Container {
> -	return &Container{dir: dir, uids: uidstore.NewStore(), log: l}
> +func NewContainer(dir string, l *log.Logger) (*Container, error) {
> +	f, err := os.Open(dir)
> +	if err != nil {
> +		return nil, err
> +	}
> +	s, _ := f.Stat()
Why are you ignoring the error instead of returning it?
If the error is non nil, chances are that s is the zero valued struct, which
isn't overly useful but you still try to call methods on it later.

> +	f.Close()

defer please, and right after opening it (after the error check).
Not that important here, but you might as well get into the habit

> +	if !s.IsDir() {
> +		return nil, fmt.Errorf("Given maildir '%s' not a directory", dir)
> +	}
> +	return &Container{dir: dir, uids: uidstore.NewStore(), log: l}, nil
>  }

Greetings,
Reto
Details
Message ID
<20200725111618.ed381ca9a04262190c122fb0@iki.fi>
In-Reply-To
<20200725062316.wytua7hzqrydwd7k@feather.localdomain> (view parent)
DKIM signature
missing
Download raw message
Hi,

On Sat, 25 Jul 2020 08:23:16 +0200
Reto <reto@labrat.space> wrote:

> Hi,
> Thanks for the update
> 
> On Fri, Jul 24, 2020 at 10:38:50PM +0300, Tero Koskinen wrote:
> > +	f, err := os.Open(dir)
> > +	if err != nil {
> > +		return nil, err
> > +	}
> > +	s, _ := f.Stat()
> Why are you ignoring the error instead of returning it?
> If the error is non nil, chances are that s is the zero valued struct, which
> isn't overly useful but you still try to call methods on it later.

I added the error checking in v3.

My initial assumption was that fstat() shouldn't fail if we have
successfully opened the directory. But now, after checking the manual
pages, I noticed at least on OpenBSD fstat() can return EIO if there
is a file system reading error during fstat() call.


>  > +	f.Close()
> 
> defer please, and right after opening it (after the error check).

Added defer in v3.

Yours,
 Tero
Reply to thread Export thread (mbox)