func (d *driver) PutContent(ctx context.Context, subPath string, contents []byte) error {
	writer, err := d.Writer(ctx, subPath, false)
	if err != nil {
		return err
	}
	defer writer.Close()
	_, err = io.Copy(writer, bytes.NewReader(contents))
	if err != nil {
		writer.Cancel()
		return err
	}
	return writer.Commit()
}
PutContent stores the []byte content at a location designated by "path".
package filesystem
import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path"
	"reflect"
	"strconv"
	"time"
	"github.com/docker/distribution/context"
	storagedriver "github.com/docker/distribution/registry/storage/driver"
	"github.com/docker/distribution/registry/storage/driver/base"
	"github.com/docker/distribution/registry/storage/driver/factory"
)
const (
	driverName           = "filesystem"
	defaultRootDirectory = "/var/lib/registry"
	defaultMaxThreads    = uint64(100)
	minThreads = uint64(25)
)
type DriverParameters struct {
	RootDirectory string
	MaxThreads    uint64
}
func init() {
	factory.Register(driverName, &filesystemDriverFactory{})
}
type filesystemDriverFactory struct{}
func (factory *filesystemDriverFactory) Create(parameters map[string]interface{}) (storagedriver.StorageDriver, error) {
	return FromParameters(parameters)
}
type driver struct {
	rootDirectory string
}
type baseEmbed struct {
	base.Base
}
type Driver struct {
	baseEmbed
}
func FromParameters(parameters map[string]interface{}) (*Driver, error) {
	params, err := fromParametersImpl(parameters)
	if err != nil || params == nil {
		return nil, err
	}
	return New(*params), nil
}
func fromParametersImpl(parameters map[string]interface{}) (*DriverParameters, error) {
	var (
		err           error
		maxThreads    = defaultMaxThreads
		rootDirectory = defaultRootDirectory
	)
	if parameters != nil {
		if rootDir, ok := parameters["rootdirectory"]; ok {
			rootDirectory = fmt.Sprint(rootDir)
		}
		threads := parameters["maxthreads"]
		switch v := threads.(type) {
		case string:
			if maxThreads, err = strconv.ParseUint(v, 0, 64); err != nil {
				return nil, fmt.Errorf("maxthreads parameter must be an integer, %v invalid", threads)
			}
		case uint64:
			maxThreads = v
		case int, int32, int64:
			val := reflect.ValueOf(v).Convert(reflect.TypeOf(threads)).Int()
			if val > 0 {
				maxThreads = uint64(val)
			}
		case uint, uint32:
			maxThreads = reflect.ValueOf(v).Convert(reflect.TypeOf(threads)).Uint()
		case nil:
		default:
			return nil, fmt.Errorf("invalid value for maxthreads: %#v", threads)
		}
		if maxThreads < minThreads {
			maxThreads = minThreads
		}
	}
	params := &DriverParameters{
		RootDirectory: rootDirectory,
		MaxThreads:    maxThreads,
	}
	return params, nil
}
func New(params DriverParameters) *Driver {
	fsDriver := &driver{rootDirectory: params.RootDirectory}
	return &Driver{
		baseEmbed: baseEmbed{
			Base: base.Base{
				StorageDriver: base.NewRegulator(fsDriver, params.MaxThreads),
			},
		},
	}
}
func (d *driver) Name() string {
	return driverName
}
func (d *driver) GetContent(ctx context.Context, path string) ([]byte, error) {
	rc, err := d.Reader(ctx, path, 0)
	if err != nil {
		return nil, err
	}
	defer rc.Close()
	p, err := ioutil.ReadAll(rc)
	if err != nil {
		return nil, err
	}
	return p, nil
}