...

Source file src/github.com/docker/distribution/registry/storage/driver/inmemory/mfs.go

Documentation: github.com/docker/distribution/registry/storage/driver/inmemory

     1  package inmemory
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"path"
     7  	"sort"
     8  	"strings"
     9  	"time"
    10  )
    11  
    12  var (
    13  	errExists    = fmt.Errorf("exists")
    14  	errNotExists = fmt.Errorf("notexists")
    15  	errIsNotDir  = fmt.Errorf("notdir")
    16  	errIsDir     = fmt.Errorf("isdir")
    17  )
    18  
    19  type node interface {
    20  	name() string
    21  	path() string
    22  	isdir() bool
    23  	modtime() time.Time
    24  }
    25  
    26  // dir is the central type for the memory-based  storagedriver. All operations
    27  // are dispatched from a root dir.
    28  type dir struct {
    29  	common
    30  
    31  	// TODO(stevvooe): Use sorted slice + search.
    32  	children map[string]node
    33  }
    34  
    35  var _ node = &dir{}
    36  
    37  func (d *dir) isdir() bool {
    38  	return true
    39  }
    40  
    41  // add places the node n into dir d.
    42  func (d *dir) add(n node) {
    43  	if d.children == nil {
    44  		d.children = make(map[string]node)
    45  	}
    46  
    47  	d.children[n.name()] = n
    48  	d.mod = time.Now()
    49  }
    50  
    51  // find searches for the node, given path q in dir. If the node is found, it
    52  // will be returned. If the node is not found, the closet existing parent. If
    53  // the node is found, the returned (node).path() will match q.
    54  func (d *dir) find(q string) node {
    55  	q = strings.Trim(q, "/")
    56  	i := strings.Index(q, "/")
    57  
    58  	if q == "" {
    59  		return d
    60  	}
    61  
    62  	if i == 0 {
    63  		panic("shouldn't happen, no root paths")
    64  	}
    65  
    66  	var component string
    67  	if i < 0 {
    68  		// No more path components
    69  		component = q
    70  	} else {
    71  		component = q[:i]
    72  	}
    73  
    74  	child, ok := d.children[component]
    75  	if !ok {
    76  		// Node was not found. Return p and the current node.
    77  		return d
    78  	}
    79  
    80  	if child.isdir() {
    81  		// traverse down!
    82  		q = q[i+1:]
    83  		return child.(*dir).find(q)
    84  	}
    85  
    86  	return child
    87  }
    88  
    89  func (d *dir) list(p string) ([]string, error) {
    90  	n := d.find(p)
    91  
    92  	if n.path() != p {
    93  		return nil, errNotExists
    94  	}
    95  
    96  	if !n.isdir() {
    97  		return nil, errIsNotDir
    98  	}
    99  
   100  	var children []string
   101  	for _, child := range n.(*dir).children {
   102  		children = append(children, child.path())
   103  	}
   104  
   105  	sort.Strings(children)
   106  	return children, nil
   107  }
   108  
   109  // mkfile or return the existing one. returns an error if it exists and is a
   110  // directory. Essentially, this is open or create.
   111  func (d *dir) mkfile(p string) (*file, error) {
   112  	n := d.find(p)
   113  	if n.path() == p {
   114  		if n.isdir() {
   115  			return nil, errIsDir
   116  		}
   117  
   118  		return n.(*file), nil
   119  	}
   120  
   121  	dirpath, filename := path.Split(p)
   122  	// Make any non-existent directories
   123  	n, err := d.mkdirs(dirpath)
   124  	if err != nil {
   125  		return nil, err
   126  	}
   127  
   128  	dd := n.(*dir)
   129  	n = &file{
   130  		common: common{
   131  			p:   path.Join(dd.path(), filename),
   132  			mod: time.Now(),
   133  		},
   134  	}
   135  
   136  	dd.add(n)
   137  	return n.(*file), nil
   138  }
   139  
   140  // mkdirs creates any missing directory entries in p and returns the result.
   141  func (d *dir) mkdirs(p string) (*dir, error) {
   142  	p = normalize(p)
   143  
   144  	n := d.find(p)
   145  
   146  	if !n.isdir() {
   147  		// Found something there
   148  		return nil, errIsNotDir
   149  	}
   150  
   151  	if n.path() == p {
   152  		return n.(*dir), nil
   153  	}
   154  
   155  	dd := n.(*dir)
   156  
   157  	relative := strings.Trim(strings.TrimPrefix(p, n.path()), "/")
   158  
   159  	if relative == "" {
   160  		return dd, nil
   161  	}
   162  
   163  	components := strings.Split(relative, "/")
   164  	for _, component := range components {
   165  		d, err := dd.mkdir(component)
   166  
   167  		if err != nil {
   168  			// This should actually never happen, since there are no children.
   169  			return nil, err
   170  		}
   171  		dd = d
   172  	}
   173  
   174  	return dd, nil
   175  }
   176  
   177  // mkdir creates a child directory under d with the given name.
   178  func (d *dir) mkdir(name string) (*dir, error) {
   179  	if name == "" {
   180  		return nil, fmt.Errorf("invalid dirname")
   181  	}
   182  
   183  	_, ok := d.children[name]
   184  	if ok {
   185  		return nil, errExists
   186  	}
   187  
   188  	child := &dir{
   189  		common: common{
   190  			p:   path.Join(d.path(), name),
   191  			mod: time.Now(),
   192  		},
   193  	}
   194  	d.add(child)
   195  	d.mod = time.Now()
   196  
   197  	return child, nil
   198  }
   199  
   200  func (d *dir) move(src, dst string) error {
   201  	dstDirname, _ := path.Split(dst)
   202  
   203  	dp, err := d.mkdirs(dstDirname)
   204  	if err != nil {
   205  		return err
   206  	}
   207  
   208  	srcDirname, srcFilename := path.Split(src)
   209  	sp := d.find(srcDirname)
   210  
   211  	if normalize(srcDirname) != normalize(sp.path()) {
   212  		return errNotExists
   213  	}
   214  
   215  	spd, ok := sp.(*dir)
   216  	if !ok {
   217  		return errIsNotDir // paranoid.
   218  	}
   219  
   220  	s, ok := spd.children[srcFilename]
   221  	if !ok {
   222  		return errNotExists
   223  	}
   224  
   225  	delete(spd.children, srcFilename)
   226  
   227  	switch n := s.(type) {
   228  	case *dir:
   229  		n.p = dst
   230  	case *file:
   231  		n.p = dst
   232  	}
   233  
   234  	dp.add(s)
   235  
   236  	return nil
   237  }
   238  
   239  func (d *dir) delete(p string) error {
   240  	dirname, filename := path.Split(p)
   241  	parent := d.find(dirname)
   242  
   243  	if normalize(dirname) != normalize(parent.path()) {
   244  		return errNotExists
   245  	}
   246  
   247  	if _, ok := parent.(*dir).children[filename]; !ok {
   248  		return errNotExists
   249  	}
   250  
   251  	delete(parent.(*dir).children, filename)
   252  	return nil
   253  }
   254  
   255  func (d *dir) String() string {
   256  	return fmt.Sprintf("&dir{path: %v, children: %v}", d.p, d.children)
   257  }
   258  
   259  // file stores actual data in the fs tree. It acts like an open, seekable file
   260  // where operations are conducted through ReadAt and WriteAt. Use it with
   261  // SectionReader for the best effect.
   262  type file struct {
   263  	common
   264  	data []byte
   265  }
   266  
   267  var _ node = &file{}
   268  
   269  func (f *file) isdir() bool {
   270  	return false
   271  }
   272  
   273  func (f *file) truncate() {
   274  	f.data = f.data[:0]
   275  }
   276  
   277  func (f *file) sectionReader(offset int64) io.Reader {
   278  	return io.NewSectionReader(f, offset, int64(len(f.data))-offset)
   279  }
   280  
   281  func (f *file) ReadAt(p []byte, offset int64) (n int, err error) {
   282  	if offset >= int64(len(f.data)) {
   283  		return 0, io.EOF
   284  	}
   285  	return copy(p, f.data[offset:]), nil
   286  }
   287  
   288  func (f *file) WriteAt(p []byte, offset int64) (n int, err error) {
   289  	off := int(offset)
   290  	if cap(f.data) < off+len(p) {
   291  		data := make([]byte, len(f.data), off+len(p))
   292  		copy(data, f.data)
   293  		f.data = data
   294  	}
   295  
   296  	f.mod = time.Now()
   297  	f.data = f.data[:off+len(p)]
   298  
   299  	return copy(f.data[off:off+len(p)], p), nil
   300  }
   301  
   302  func (f *file) String() string {
   303  	return fmt.Sprintf("&file{path: %q}", f.p)
   304  }
   305  
   306  // common provides shared fields and methods for node implementations.
   307  type common struct {
   308  	p   string
   309  	mod time.Time
   310  }
   311  
   312  func (c *common) name() string {
   313  	_, name := path.Split(c.p)
   314  	return name
   315  }
   316  
   317  func (c *common) path() string {
   318  	return c.p
   319  }
   320  
   321  func (c *common) modtime() time.Time {
   322  	return c.mod
   323  }
   324  
   325  func normalize(p string) string {
   326  	return "/" + strings.Trim(p, "/")
   327  }
   328  

View as plain text