Commit | Line | Data |
---|---|---|
36457566 LC |
1 | #include "store-api.hh" |
2 | #include "globals.hh" | |
3 | #include "util.hh" | |
4 | ||
5 | #include <climits> | |
6 | ||
7 | ||
8 | namespace nix { | |
9 | ||
10 | ||
11 | GCOptions::GCOptions() | |
12 | { | |
13 | action = gcDeleteDead; | |
14 | ignoreLiveness = false; | |
15 | maxFreed = ULLONG_MAX; | |
16 | } | |
17 | ||
18 | ||
19 | bool isInStore(const Path & path) | |
20 | { | |
21 | return isInDir(path, settings.nixStore); | |
22 | } | |
23 | ||
24 | ||
25 | bool isStorePath(const Path & path) | |
26 | { | |
27 | return isInStore(path) | |
28 | && path.find('/', settings.nixStore.size() + 1) == Path::npos; | |
29 | } | |
30 | ||
31 | ||
32 | void assertStorePath(const Path & path) | |
33 | { | |
34 | if (!isStorePath(path)) | |
8327e733 | 35 | throw Error(format("path `%1%' is not in the store") % path); |
36457566 LC |
36 | } |
37 | ||
38 | ||
39 | Path toStorePath(const Path & path) | |
40 | { | |
41 | if (!isInStore(path)) | |
8327e733 | 42 | throw Error(format("path `%1%' is not in the store") % path); |
36457566 LC |
43 | Path::size_type slash = path.find('/', settings.nixStore.size() + 1); |
44 | if (slash == Path::npos) | |
45 | return path; | |
46 | else | |
47 | return Path(path, 0, slash); | |
48 | } | |
49 | ||
50 | ||
36457566 LC |
51 | string storePathToName(const Path & path) |
52 | { | |
53 | assertStorePath(path); | |
54 | return string(path, settings.nixStore.size() + 34); | |
55 | } | |
56 | ||
57 | ||
58 | void checkStoreName(const string & name) | |
59 | { | |
60 | string validChars = "+-._?="; | |
61 | /* Disallow names starting with a dot for possible security | |
62 | reasons (e.g., "." and ".."). */ | |
63 | if (string(name, 0, 1) == ".") | |
76533c52 | 64 | throw Error(format("invalid name: `%1%'") % name); |
36457566 LC |
65 | foreach (string::const_iterator, i, name) |
66 | if (!((*i >= 'A' && *i <= 'Z') || | |
67 | (*i >= 'a' && *i <= 'z') || | |
68 | (*i >= '0' && *i <= '9') || | |
69 | validChars.find(*i) != string::npos)) | |
70 | { | |
71 | throw Error(format("invalid character `%1%' in name `%2%'") | |
72 | % *i % name); | |
73 | } | |
74 | } | |
75 | ||
76 | ||
77 | /* Store paths have the following form: | |
78 | ||
79 | <store>/<h>-<name> | |
80 | ||
81 | where | |
82 | ||
8327e733 | 83 | <store> = the location of the store, usually /gnu/store |
36457566 LC |
84 | |
85 | <name> = a human readable name for the path, typically obtained | |
86 | from the name attribute of the derivation, or the name of the | |
87 | source file from which the store path is created. For derivation | |
88 | outputs other than the default "out" output, the string "-<id>" | |
89 | is suffixed to <name>. | |
90 | ||
91 | <h> = base-32 representation of the first 160 bits of a SHA-256 | |
92 | hash of <s>; the hash part of the store name | |
93 | ||
94 | <s> = the string "<type>:sha256:<h2>:<store>:<name>"; | |
95 | note that it includes the location of the store as well as the | |
96 | name to make sure that changes to either of those are reflected | |
97 | in the hash (e.g. you won't get /nix/store/<h>-name1 and | |
98 | /nix/store/<h>-name2 with equal hash parts). | |
99 | ||
100 | <type> = one of: | |
101 | "text:<r1>:<r2>:...<rN>" | |
102 | for plain text files written to the store using | |
103 | addTextToStore(); <r1> ... <rN> are the references of the | |
104 | path. | |
105 | "source" | |
106 | for paths copied to the store using addToStore() when recursive | |
107 | = true and hashAlgo = "sha256" | |
108 | "output:<id>" | |
109 | for either the outputs created by derivations, OR paths copied | |
110 | to the store using addToStore() with recursive != true or | |
111 | hashAlgo != "sha256" (in that case "source" is used; it's | |
112 | silly, but it's done that way for compatibility). <id> is the | |
113 | name of the output (usually, "out"). | |
114 | ||
115 | <h2> = base-16 representation of a SHA-256 hash of: | |
116 | if <type> = "text:...": | |
117 | the string written to the resulting store path | |
118 | if <type> = "source": | |
119 | the serialisation of the path from which this store path is | |
120 | copied, as returned by hashPath() | |
121 | if <type> = "output:out": | |
122 | for non-fixed derivation outputs: | |
123 | the derivation (see hashDerivationModulo() in | |
124 | primops.cc) | |
125 | for paths copied by addToStore() or produced by fixed-output | |
126 | derivations: | |
127 | the string "fixed:out:<rec><algo>:<hash>:", where | |
128 | <rec> = "r:" for recursive (path) hashes, or "" or flat | |
129 | (file) hashes | |
130 | <algo> = "md5", "sha1" or "sha256" | |
131 | <hash> = base-16 representation of the path or flat hash of | |
132 | the contents of the path (or expected contents of the | |
133 | path for fixed-output derivations) | |
134 | ||
135 | It would have been nicer to handle fixed-output derivations under | |
136 | "source", e.g. have something like "source:<rec><algo>", but we're | |
137 | stuck with this for now... | |
138 | ||
139 | The main reason for this way of computing names is to prevent name | |
140 | collisions (for security). For instance, it shouldn't be feasible | |
141 | to come up with a derivation whose output path collides with the | |
142 | path for a copied source. The former would have a <s> starting with | |
143 | "output:out:", while the latter would have a <2> starting with | |
144 | "source:". | |
145 | */ | |
146 | ||
147 | ||
148 | Path makeStorePath(const string & type, | |
149 | const Hash & hash, const string & name) | |
150 | { | |
151 | /* e.g., "source:sha256:1abc...:/nix/store:foo.tar.gz" */ | |
152 | string s = type + ":sha256:" + printHash(hash) + ":" | |
153 | + settings.nixStore + ":" + name; | |
154 | ||
155 | checkStoreName(name); | |
156 | ||
157 | return settings.nixStore + "/" | |
158 | + printHash32(compressHash(hashString(htSHA256, s), 20)) | |
159 | + "-" + name; | |
160 | } | |
161 | ||
162 | ||
163 | Path makeOutputPath(const string & id, | |
164 | const Hash & hash, const string & name) | |
165 | { | |
166 | return makeStorePath("output:" + id, hash, | |
167 | name + (id == "out" ? "" : "-" + id)); | |
168 | } | |
169 | ||
170 | ||
171 | Path makeFixedOutputPath(bool recursive, | |
172 | HashType hashAlgo, Hash hash, string name) | |
173 | { | |
174 | return hashAlgo == htSHA256 && recursive | |
175 | ? makeStorePath("source", hash, name) | |
176 | : makeStorePath("output:out", hashString(htSHA256, | |
177 | "fixed:out:" + (recursive ? (string) "r:" : "") + | |
178 | printHashType(hashAlgo) + ":" + printHash(hash) + ":"), | |
179 | name); | |
180 | } | |
181 | ||
182 | ||
36457566 LC |
183 | Path computeStorePathForText(const string & name, const string & s, |
184 | const PathSet & references) | |
185 | { | |
186 | Hash hash = hashString(htSHA256, s); | |
187 | /* Stuff the references (if any) into the type. This is a bit | |
188 | hacky, but we can't put them in `s' since that would be | |
189 | ambiguous. */ | |
190 | string type = "text"; | |
191 | foreach (PathSet::const_iterator, i, references) { | |
192 | type += ":"; | |
193 | type += *i; | |
194 | } | |
195 | return makeStorePath(type, hash, name); | |
196 | } | |
197 | ||
198 | ||
199 | /* Return a string accepted by decodeValidPathInfo() that | |
200 | registers the specified paths as valid. Note: it's the | |
201 | responsibility of the caller to provide a closure. */ | |
202 | string StoreAPI::makeValidityRegistration(const PathSet & paths, | |
203 | bool showDerivers, bool showHash) | |
204 | { | |
205 | string s = ""; | |
206 | ||
207 | foreach (PathSet::iterator, i, paths) { | |
208 | s += *i + "\n"; | |
209 | ||
210 | ValidPathInfo info = queryPathInfo(*i); | |
211 | ||
212 | if (showHash) { | |
213 | s += printHash(info.hash) + "\n"; | |
214 | s += (format("%1%\n") % info.narSize).str(); | |
215 | } | |
216 | ||
217 | Path deriver = showDerivers ? info.deriver : ""; | |
218 | s += deriver + "\n"; | |
219 | ||
220 | s += (format("%1%\n") % info.references.size()).str(); | |
221 | ||
222 | foreach (PathSet::iterator, j, info.references) | |
223 | s += *j + "\n"; | |
224 | } | |
225 | ||
226 | return s; | |
227 | } | |
228 | ||
36457566 LC |
229 | string showPaths(const PathSet & paths) |
230 | { | |
231 | string s; | |
232 | foreach (PathSet::const_iterator, i, paths) { | |
233 | if (s.size() != 0) s += ", "; | |
234 | s += "`" + *i + "'"; | |
235 | } | |
236 | return s; | |
237 | } | |
238 | ||
239 | ||
240 | void exportPaths(StoreAPI & store, const Paths & paths, | |
241 | bool sign, Sink & sink) | |
242 | { | |
243 | foreach (Paths::const_iterator, i, paths) { | |
244 | writeInt(1, sink); | |
245 | store.exportPath(*i, sign, sink); | |
246 | } | |
247 | writeInt(0, sink); | |
248 | } | |
249 | ||
20b97819 LC |
250 | Path readStorePath(Source & from) |
251 | { | |
252 | Path path = readString(from); | |
253 | assertStorePath(path); | |
254 | return path; | |
255 | } | |
256 | ||
257 | ||
258 | template<class T> T readStorePaths(Source & from) | |
259 | { | |
260 | T paths = readStrings<T>(from); | |
261 | foreach (typename T::iterator, i, paths) assertStorePath(*i); | |
262 | return paths; | |
263 | } | |
264 | ||
265 | template PathSet readStorePaths(Source & from); | |
36457566 LC |
266 | |
267 | } | |
268 | ||
269 | ||
270 | #include "local-store.hh" | |
271 | #include "serialise.hh" | |
36457566 LC |
272 | |
273 | ||
274 | namespace nix { | |
275 | ||
276 | ||
277 | std::shared_ptr<StoreAPI> store; | |
278 | ||
279 | ||
280 | std::shared_ptr<StoreAPI> openStore(bool reserveSpace) | |
281 | { | |
20b97819 | 282 | return std::shared_ptr<StoreAPI>(new LocalStore(reserveSpace)); |
36457566 LC |
283 | } |
284 | ||
285 | ||
286 | } |