...
1 package storage
2
3 import (
4 "context"
5 "errors"
6 "io"
7 "path"
8 "strings"
9
10 "github.com/distribution/reference"
11 "github.com/docker/distribution/registry/storage/driver"
12 )
13
14
15
16
17 func (reg *registry) Repositories(ctx context.Context, repos []string, last string) (n int, err error) {
18 var finishedWalk bool
19 var foundRepos []string
20
21 if len(repos) == 0 {
22 return 0, errors.New("no space in slice")
23 }
24
25 root, err := pathFor(repositoriesRootPathSpec{})
26 if err != nil {
27 return 0, err
28 }
29
30 err = reg.blobStore.driver.Walk(ctx, root, func(fileInfo driver.FileInfo) error {
31 err := handleRepository(fileInfo, root, last, func(repoPath string) error {
32 foundRepos = append(foundRepos, repoPath)
33 return nil
34 })
35 if err != nil {
36 return err
37 }
38
39
40 if len(foundRepos) == len(repos) {
41 finishedWalk = true
42 return driver.ErrSkipDir
43 }
44
45 return nil
46 })
47
48 n = copy(repos, foundRepos)
49
50 if err != nil {
51 return n, err
52 } else if !finishedWalk {
53
54 return n, io.EOF
55 }
56
57 return n, err
58 }
59
60
61 func (reg *registry) Enumerate(ctx context.Context, ingester func(string) error) error {
62 root, err := pathFor(repositoriesRootPathSpec{})
63 if err != nil {
64 return err
65 }
66
67 err = reg.blobStore.driver.Walk(ctx, root, func(fileInfo driver.FileInfo) error {
68 return handleRepository(fileInfo, root, "", ingester)
69 })
70
71 return err
72 }
73
74
75 func (reg *registry) Remove(ctx context.Context, name reference.Named) error {
76 root, err := pathFor(repositoriesRootPathSpec{})
77 if err != nil {
78 return err
79 }
80 repoDir := path.Join(root, name.Name())
81 return reg.driver.Delete(ctx, repoDir)
82 }
83
84
85
86
87
88 func lessPath(a, b string) bool {
89
90 return compareReplaceInline(a, b, '/', '\x00') < 0
91 }
92
93
94
95 func compareReplaceInline(s1, s2 string, old, new byte) int {
96
97
98
99
100 l := len(s1)
101 if len(s2) < l {
102 l = len(s2)
103 }
104
105 for i := 0; i < l; i++ {
106 c1, c2 := s1[i], s2[i]
107 if c1 == old {
108 c1 = new
109 }
110
111 if c2 == old {
112 c2 = new
113 }
114
115 if c1 < c2 {
116 return -1
117 }
118
119 if c1 > c2 {
120 return +1
121 }
122 }
123
124 if len(s1) < len(s2) {
125 return -1
126 }
127
128 if len(s1) > len(s2) {
129 return +1
130 }
131
132 return 0
133 }
134
135
136
137
138
139 func handleRepository(fileInfo driver.FileInfo, root, last string, fn func(repoPath string) error) error {
140 filePath := fileInfo.Path()
141
142
143 repo := filePath[len(root)+1:]
144
145 _, file := path.Split(repo)
146 if file == "_layers" {
147 repo = strings.TrimSuffix(repo, "/_layers")
148 if lessPath(last, repo) {
149 if err := fn(repo); err != nil {
150 return err
151 }
152 }
153 return driver.ErrSkipDir
154 } else if strings.HasPrefix(file, "_") {
155 return driver.ErrSkipDir
156 }
157
158 return nil
159 }
160
View as plain text