|
@@ -11,7 +11,9 @@ import (
|
|
|
"path/filepath"
|
|
|
"sync"
|
|
|
|
|
|
+ derr "github.com/docker/docker/errors"
|
|
|
"github.com/docker/docker/pkg/idtools"
|
|
|
+ "github.com/docker/docker/utils"
|
|
|
"github.com/docker/docker/volume"
|
|
|
)
|
|
|
|
|
@@ -23,8 +25,14 @@ const (
|
|
|
volumesPathName = "volumes"
|
|
|
)
|
|
|
|
|
|
-// ErrNotFound is the typed error returned when the requested volume name can't be found
|
|
|
-var ErrNotFound = errors.New("volume not found")
|
|
|
+var (
|
|
|
+ // ErrNotFound is the typed error returned when the requested volume name can't be found
|
|
|
+ ErrNotFound = errors.New("volume not found")
|
|
|
+ // volumeNameRegex ensures the name asigned for the volume is valid.
|
|
|
+ // This name is used to create the bind directory, so we need to avoid characters that
|
|
|
+ // would make the path to escape the root directory.
|
|
|
+ volumeNameRegex = utils.RestrictedNamePattern
|
|
|
+)
|
|
|
|
|
|
// New instantiates a new Root instance with the provided scope. Scope
|
|
|
// is the base path that the Root instance uses to store its
|
|
@@ -96,6 +104,10 @@ func (r *Root) Name() string {
|
|
|
// the underlying directory tree required for this volume in the
|
|
|
// process.
|
|
|
func (r *Root) Create(name string, _ map[string]string) (volume.Volume, error) {
|
|
|
+ if err := r.validateName(name); err != nil {
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+
|
|
|
r.m.Lock()
|
|
|
defer r.m.Unlock()
|
|
|
|
|
@@ -174,6 +186,13 @@ func (r *Root) Get(name string) (volume.Volume, error) {
|
|
|
return v, nil
|
|
|
}
|
|
|
|
|
|
+func (r *Root) validateName(name string) error {
|
|
|
+ if !volumeNameRegex.MatchString(name) {
|
|
|
+ return derr.ErrorCodeVolumeName.WithArgs(name, utils.RestrictedNameChars)
|
|
|
+ }
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
// localVolume implements the Volume interface from the volume package and
|
|
|
// represents the volumes created by Root.
|
|
|
type localVolume struct {
|