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