func (fs *LocalFS) List() (ids []string, err error) {
	err = filepath.Walk(fs.storePath,
		func(path string, info os.FileInfo, err error) error {
			if err != nil {
				return err
			}
			if !info.IsDir() && strings.HasSuffix(info.Name(), imgSfx) {
				ids = append(ids, info.Name())
			}
			return nil
		})
	return ids, errors.Wrap(err, "can't list avatars")
}
List all avatars (ids) on local file system
note: id includes .image suffix
package avatar
import (
	"fmt"
	"hash/crc64"
	"io"
	"os"
	"path"
	"path/filepath"
	"strconv"
	"strings"
	"sync"
	"github.com/pkg/errors"
)
type LocalFS struct {
	storePath string
	ctcTable  *crc64.Table
	once      sync.Once
}
func NewLocalFS(storePath string) *LocalFS {
	return &LocalFS{storePath: storePath}
}
func (fs *LocalFS) Put(userID string, reader io.Reader) (avatar string, err error) {
	if reader == nil {
		return "", errors.New("empty reader")
	}
	id := encodeID(userID)
	location := fs.location(id)  
	if e := os.MkdirAll(location, 0750); e != nil {
		return "", errors.Wrapf(e, "failed to mkdir avatar location %s", location)
	}
	avFile := path.Join(location, id+imgSfx)
	fh, err := os.Create(avFile)
	if err != nil {
		return "", errors.Wrapf(err, "can't create file %s", avFile)
	}
	defer func() {
		if e := fh.Close(); e != nil {
			err = errors.Wrapf(err, "can't close avatar file %s", avFile)
		}
	}()
	if _, err = io.Copy(fh, reader); err != nil {
		return "", errors.Wrapf(err, "can't save file %s", avFile)
	}
	return id + imgSfx, nil
}
func (fs *LocalFS) Get(avatar string) (reader io.ReadCloser, size int, err error) {
	location := fs.location(strings.TrimSuffix(avatar, imgSfx))
	fh, err := os.Open(path.Join(location, avatar))  
	if err != nil {
		return nil, 0, errors.Wrapf(err, "can't load avatar %s, id", avatar)
	}
	if fi, e := fh.Stat(); e == nil {
		size = int(fi.Size())
	}
	return fh, size, nil
}
func (fs *LocalFS) ID(avatar string) (id string) {
	location := fs.location(strings.TrimSuffix(avatar, imgSfx))
	avFile := path.Join(location, avatar)
	fi, err := os.Stat(avFile)
	if err != nil {
		return encodeID(avatar)
	}
	return encodeID(avatar + strconv.FormatInt(fi.ModTime().Unix(), 10))
}
func (fs *LocalFS) Remove(avatar string) error {
	location := fs.location(strings.TrimSuffix(avatar, imgSfx))
	avFile := path.Join(location, avatar)
	return os.Remove(avFile)
}