1 #pragma once
2 
3 #include "hash.hh"
4 #include "serialise.hh"
5 #include "crypto.hh"
6 #include "lru-cache.hh"
7 #include "sync.hh"
8 #include "globals.hh"
9 #include "config.hh"
10 
11 #include <atomic>
12 #include <limits>
13 #include <map>
14 #include <unordered_map>
15 #include <unordered_set>
16 #include <memory>
17 #include <string>
18 #include <chrono>
19 
20 
21 namespace nix {
22 
23 
24 MakeError(SubstError, Error)
25 MakeError(BuildError, Error) /* denotes a permanent build failure */
26 MakeError(InvalidPath, Error)
27 MakeError(Unsupported, Error)
28 MakeError(SubstituteGone, Error)
29 MakeError(SubstituterDisabled, Error)
30 
31 
32 struct BasicDerivation;
33 struct Derivation;
34 class FSAccessor;
35 class NarInfoDiskCache;
36 class Store;
37 class JSONPlaceholder;
38 
39 
40 enum RepairFlag : bool { NoRepair = false, Repair = true };
41 enum CheckSigsFlag : bool { NoCheckSigs = false, CheckSigs = true };
42 enum SubstituteFlag : bool { NoSubstitute = false, Substitute = true };
43 enum AllowInvalidFlag : bool { DisallowInvalid = false, AllowInvalid = true };
44 
45 
46 /* Size of the hash part of store paths, in base-32 characters. */
47 const size_t storePathHashLen = 32; // i.e. 160 bits
48 
49 /* Magic header of exportPath() output (obsolete). */
50 const uint32_t exportMagic = 0x4558494e;
51 
52 
53 typedef std::unordered_map<Path, std::unordered_set<std::string>> Roots;
54 
55 
56 struct GCOptions
57 {
58     /* Garbage collector operation:
59 
60        - `gcReturnLive': return the set of paths reachable from
61          (i.e. in the closure of) the roots.
62 
63        - `gcReturnDead': return the set of paths not reachable from
64          the roots.
65 
66        - `gcDeleteDead': actually delete the latter set.
67 
68        - `gcDeleteSpecific': delete the paths listed in
69           `pathsToDelete', insofar as they are not reachable.
70     */
71     typedef enum {
72         gcReturnLive,
73         gcReturnDead,
74         gcDeleteDead,
75         gcDeleteSpecific,
76     } GCAction;
77 
78     GCAction action{gcDeleteDead};
79 
80     /* If `ignoreLiveness' is set, then reachability from the roots is
81        ignored (dangerous!).  However, the paths must still be
82        unreferenced *within* the store (i.e., there can be no other
83        store paths that depend on them). */
84     bool ignoreLiveness{false};
85 
86     /* For `gcDeleteSpecific', the paths to delete. */
87     PathSet pathsToDelete;
88 
89     /* Stop after at least `maxFreed' bytes have been freed. */
90     unsigned long long maxFreed{std::numeric_limits<unsigned long long>::max()};
91 };
92 
93 
94 struct GCResults
95 {
96     /* Depending on the action, the GC roots, or the paths that would
97        be or have been deleted. */
98     PathSet paths;
99 
100     /* For `gcReturnDead', `gcDeleteDead' and `gcDeleteSpecific', the
101        number of bytes that would be or was freed. */
102     unsigned long long bytesFreed = 0;
103 };
104 
105 
106 struct SubstitutablePathInfo
107 {
108     Path deriver;
109     PathSet references;
110     unsigned long long downloadSize; /* 0 = unknown or inapplicable */
111     unsigned long long narSize; /* 0 = unknown */
112 };
113 
114 typedef std::map<Path, SubstitutablePathInfo> SubstitutablePathInfos;
115 
116 
117 struct ValidPathInfo
118 {
119     Path path;
120     Path deriver;
121     Hash narHash;
122     PathSet references;
123     time_t registrationTime = 0;
124     uint64_t narSize = 0; // 0 = unknown
125     uint64_t id; // internal use only
126 
127     /* Whether the path is ultimately trusted, that is, it's a
128        derivation output that was built locally. */
129     bool ultimate = false;
130 
131     StringSet sigs; // note: not necessarily verified
132 
133     /* If non-empty, an assertion that the path is content-addressed,
134        i.e., that the store path is computed from a cryptographic hash
135        of the contents of the path, plus some other bits of data like
136        the "name" part of the path. Such a path doesn't need
137        signatures, since we don't have to trust anybody's claim that
138        the path is the output of a particular derivation. (In the
139        extensional store model, we have to trust that the *contents*
140        of an output path of a derivation were actually produced by
141        that derivation. In the intensional model, we have to trust
142        that a particular output path was produced by a derivation; the
143        path then implies the contents.)
144 
145        Ideally, the content-addressability assertion would just be a
146        Boolean, and the store path would be computed from
147        ‘storePathToName(path)’, ‘narHash’ and ‘references’. However,
148        1) we've accumulated several types of content-addressed paths
149        over the years; and 2) fixed-output derivations support
150        multiple hash algorithms and serialisation methods (flat file
151        vs NAR). Thus, ‘ca’ has one of the following forms:
152 
153        * ‘text:sha256:<sha256 hash of file contents>’: For paths
154          computed by makeTextPath() / addTextToStore().
155 
156        * ‘fixed:<r?>:<ht>:<h>’: For paths computed by
157          makeFixedOutputPath() / addToStore().
158     */
159     std::string ca;
160 
operator ==nix::ValidPathInfo161     bool operator == (const ValidPathInfo & i) const
162     {
163         return
164             path == i.path
165             && narHash == i.narHash
166             && references == i.references;
167     }
168 
169     /* Return a fingerprint of the store path to be used in binary
170        cache signatures. It contains the store path, the base-32
171        SHA-256 hash of the NAR serialisation of the path, the size of
172        the NAR, and the sorted references. The size field is strictly
173        speaking superfluous, but might prevent endless/excessive data
174        attacks. */
175     std::string fingerprint() const;
176 
177     void sign(const SecretKey & secretKey);
178 
179     /* Return true iff the path is verifiably content-addressed. */
180     bool isContentAddressed(const Store & store) const;
181 
182     static const size_t maxSigs = std::numeric_limits<size_t>::max();
183 
184     /* Return the number of signatures on this .narinfo that were
185        produced by one of the specified keys, or maxSigs if the path
186        is content-addressed. */
187     size_t checkSignatures(const Store & store, const PublicKeys & publicKeys) const;
188 
189     /* Verify a single signature. */
190     bool checkSignature(const PublicKeys & publicKeys, const std::string & sig) const;
191 
192     Strings shortRefs() const;
193 
~ValidPathInfonix::ValidPathInfo194     virtual ~ValidPathInfo() { }
195 };
196 
197 typedef list<ValidPathInfo> ValidPathInfos;
198 
199 
200 enum BuildMode { bmNormal, bmRepair, bmCheck };
201 
202 
203 struct BuildResult
204 {
205     /* Note: don't remove status codes, and only add new status codes
206        at the end of the list, to prevent client/server
207        incompatibilities in the nix-store --serve protocol. */
208     enum Status {
209         Built = 0,
210         Substituted,
211         AlreadyValid,
212         PermanentFailure,
213         InputRejected,
214         OutputRejected,
215         TransientFailure, // possibly transient
216         CachedFailure, // no longer used
217         TimedOut,
218         MiscFailure,
219         DependencyFailed,
220         LogLimitExceeded,
221         NotDeterministic,
222     } status = MiscFailure;
223     std::string errorMsg;
224 
225     /* How many times this build was performed. */
226     unsigned int timesBuilt = 0;
227 
228     /* If timesBuilt > 1, whether some builds did not produce the same
229        result. (Note that 'isNonDeterministic = false' does not mean
230        the build is deterministic, just that we don't have evidence of
231        non-determinism.) */
232     bool isNonDeterministic = false;
233 
234     /* The start/stop times of the build (or one of the rounds, if it
235        was repeated). */
236     time_t startTime = 0, stopTime = 0;
237 
successnix::BuildResult238     bool success() {
239         return status == Built || status == Substituted || status == AlreadyValid;
240     }
241 };
242 
243 
244 class Store : public std::enable_shared_from_this<Store>, public Config
245 {
246 public:
247 
248     typedef std::map<std::string, std::string> Params;
249 
250     const PathSetting storeDir_{this, false, settings.nixStore,
251         "store", "path to the Nix store"};
252     const Path storeDir = storeDir_;
253 
254     const Setting<int> pathInfoCacheSize{this, 65536, "path-info-cache-size", "size of the in-memory store path information cache"};
255 
256     const Setting<bool> isTrusted{this, false, "trusted", "whether paths from this store can be used as substitutes even when they lack trusted signatures"};
257 
258 protected:
259 
260     struct PathInfoCacheValue {
261 
PathInfoCacheValuenix::Store::PathInfoCacheValue262         PathInfoCacheValue(std::shared_ptr<ValidPathInfo> value) :
263             time_point(std::chrono::steady_clock::now()),
264             value(value) {}
265 
266         // Convenience constructor copying from reference
PathInfoCacheValuenix::Store::PathInfoCacheValue267         PathInfoCacheValue(const ValidPathInfo& value) :
268             PathInfoCacheValue(std::make_shared<ValidPathInfo>(value)) {}
269 
270         // Record a missing path
PathInfoCacheValuenix::Store::PathInfoCacheValue271         PathInfoCacheValue(std::nullptr_t nil) :
272             PathInfoCacheValue(std::shared_ptr<ValidPathInfo>()) {}
273 
274         // Time of cache entry creation or update(?)
275         std::chrono::time_point<std::chrono::steady_clock> time_point;
276 
277         // Null if missing
278         std::shared_ptr<ValidPathInfo> value;
279 
280         // Whether the value is valid as a cache entry. The path may not exist.
281         bool isKnownNow();
282 
283         // Past tense, because a path can only be assumed to exists when
284         // isKnownNow() && didExist()
didExistnix::Store::PathInfoCacheValue285         inline bool didExist() {
286           return value != 0;
287         }
288     };
289 
290     struct State
291     {
292         LRUCache<std::string, PathInfoCacheValue> pathInfoCache;
293     };
294 
295     Sync<State> state;
296 
297     std::shared_ptr<NarInfoDiskCache> diskCache;
298 
299     Store(const Params & params);
300 
301 public:
302 
~Store()303     virtual ~Store() { }
304 
305     virtual std::string getUri() = 0;
306 
307     /* Return true if ‘path’ is in the Nix store (but not the Nix
308        store itself). */
309     bool isInStore(const Path & path) const;
310 
311     /* Return true if ‘path’ is a store path, i.e. a direct child of
312        the Nix store. */
313     bool isStorePath(const Path & path) const;
314 
315     /* Throw an exception if ‘path’ is not a store path. */
316     void assertStorePath(const Path & path) const;
317 
318     /* Chop off the parts after the top-level store name, e.g.,
319        /nix/store/abcd-foo/bar => /nix/store/abcd-foo. */
320     Path toStorePath(const Path & path) const;
321 
322     /* Follow symlinks until we end up with a path in the Nix store. */
323     Path followLinksToStore(const Path & path) const;
324 
325     /* Same as followLinksToStore(), but apply toStorePath() to the
326        result. */
327     Path followLinksToStorePath(const Path & path) const;
328 
329     /* Constructs a unique store path name. */
330     Path makeStorePath(const string & type,
331         const Hash & hash, const string & name) const;
332 
333     Path makeOutputPath(const string & id,
334         const Hash & hash, const string & name) const;
335 
336     Path makeFixedOutputPath(bool recursive,
337         const Hash & hash, const string & name) const;
338 
339     Path makeTextPath(const string & name, const Hash & hash,
340         const PathSet & references) const;
341 
342     /* This is the preparatory part of addToStore(); it computes the
343        store path to which srcPath is to be copied.  Returns the store
344        path and the cryptographic hash of the contents of srcPath. */
345     std::pair<Path, Hash> computeStorePathForPath(const string & name,
346         const Path & srcPath, bool recursive = true,
347         HashType hashAlgo = htSHA256, PathFilter & filter = defaultPathFilter) const;
348 
349     /* Preparatory part of addTextToStore().
350 
351        !!! Computation of the path should take the references given to
352        addTextToStore() into account, otherwise we have a (relatively
353        minor) security hole: a caller can register a source file with
354        bogus references.  If there are too many references, the path may
355        not be garbage collected when it has to be (not really a problem,
356        the caller could create a root anyway), or it may be garbage
357        collected when it shouldn't be (more serious).
358 
359        Hashing the references would solve this (bogus references would
360        simply yield a different store path, so other users wouldn't be
361        affected), but it has some backwards compatibility issues (the
362        hashing scheme changes), so I'm not doing that for now. */
363     Path computeStorePathForText(const string & name, const string & s,
364         const PathSet & references) const;
365 
366     /* Check whether a path is valid. */
367     bool isValidPath(const Path & path);
368 
369 protected:
370 
371     virtual bool isValidPathUncached(const Path & path);
372 
373 public:
374 
375     /* Query which of the given paths is valid. Optionally, try to
376        substitute missing paths. */
377     virtual PathSet queryValidPaths(const PathSet & paths,
378         SubstituteFlag maybeSubstitute = NoSubstitute);
379 
380     /* Query the set of all valid paths. Note that for some store
381        backends, the name part of store paths may be omitted
382        (i.e. you'll get /nix/store/<hash> rather than
383        /nix/store/<hash>-<name>). Use queryPathInfo() to obtain the
384        full store path. */
queryAllValidPaths()385     virtual PathSet queryAllValidPaths()
386     { unsupported("queryAllValidPaths"); }
387 
388     /* Query information about a valid path. It is permitted to omit
389        the name part of the store path. */
390     ref<const ValidPathInfo> queryPathInfo(const Path & path);
391 
392     /* Asynchronous version of queryPathInfo(). */
393     void queryPathInfo(const Path & path,
394         Callback<ref<ValidPathInfo>> callback) noexcept;
395 
396 protected:
397 
398     virtual void queryPathInfoUncached(const Path & path,
399         Callback<std::shared_ptr<ValidPathInfo>> callback) noexcept = 0;
400 
401 public:
402 
403     /* Queries the set of incoming FS references for a store path.
404        The result is not cleared. */
queryReferrers(const Path & path,PathSet & referrers)405     virtual void queryReferrers(const Path & path, PathSet & referrers)
406     { unsupported("queryReferrers"); }
407 
408     /* Return all currently valid derivations that have `path' as an
409        output.  (Note that the result of `queryDeriver()' is the
410        derivation that was actually used to produce `path', which may
411        not exist anymore.) */
queryValidDerivers(const Path & path)412     virtual PathSet queryValidDerivers(const Path & path) { return {}; };
413 
414     /* Query the outputs of the derivation denoted by `path'. */
queryDerivationOutputs(const Path & path)415     virtual PathSet queryDerivationOutputs(const Path & path)
416     { unsupported("queryDerivationOutputs"); }
417 
418     /* Query the output names of the derivation denoted by `path'. */
queryDerivationOutputNames(const Path & path)419     virtual StringSet queryDerivationOutputNames(const Path & path)
420     { unsupported("queryDerivationOutputNames"); }
421 
422     /* Query the full store path given the hash part of a valid store
423        path, or "" if the path doesn't exist. */
424     virtual Path queryPathFromHashPart(const string & hashPart) = 0;
425 
426     /* Query which of the given paths have substitutes. */
querySubstitutablePaths(const PathSet & paths)427     virtual PathSet querySubstitutablePaths(const PathSet & paths) { return {}; };
428 
429     /* Query substitute info (i.e. references, derivers and download
430        sizes) of a set of paths.  If a path does not have substitute
431        info, it's omitted from the resulting ‘infos’ map. */
querySubstitutablePathInfos(const PathSet & paths,SubstitutablePathInfos & infos)432     virtual void querySubstitutablePathInfos(const PathSet & paths,
433         SubstitutablePathInfos & infos) { return; };
434 
wantMassQuery()435     virtual bool wantMassQuery() { return false; }
436 
437     /* Import a path into the store. */
438     virtual void addToStore(const ValidPathInfo & info, Source & narSource,
439         RepairFlag repair = NoRepair, CheckSigsFlag checkSigs = CheckSigs,
440         std::shared_ptr<FSAccessor> accessor = 0);
441 
442     // FIXME: remove
443     virtual void addToStore(const ValidPathInfo & info, const ref<std::string> & nar,
444         RepairFlag repair = NoRepair, CheckSigsFlag checkSigs = CheckSigs,
445         std::shared_ptr<FSAccessor> accessor = 0);
446 
447     /* Copy the contents of a path to the store and register the
448        validity the resulting path.  The resulting path is returned.
449        The function object `filter' can be used to exclude files (see
450        libutil/archive.hh). */
451     virtual Path addToStore(const string & name, const Path & srcPath,
452         bool recursive = true, HashType hashAlgo = htSHA256,
453         PathFilter & filter = defaultPathFilter, RepairFlag repair = NoRepair) = 0;
454 
455     /* Like addToStore, but the contents written to the output path is
456        a regular file containing the given string. */
457     virtual Path addTextToStore(const string & name, const string & s,
458         const PathSet & references, RepairFlag repair = NoRepair) = 0;
459 
460     /* Write a NAR dump of a store path. */
461     virtual void narFromPath(const Path & path, Sink & sink) = 0;
462 
463     /* For each path, if it's a derivation, build it.  Building a
464        derivation means ensuring that the output paths are valid.  If
465        they are already valid, this is a no-op.  Otherwise, validity
466        can be reached in two ways.  First, if the output paths is
467        substitutable, then build the path that way.  Second, the
468        output paths can be created by running the builder, after
469        recursively building any sub-derivations. For inputs that are
470        not derivations, substitute them. */
471     virtual void buildPaths(const PathSet & paths, BuildMode buildMode = bmNormal);
472 
473     /* Build a single non-materialized derivation (i.e. not from an
474        on-disk .drv file). Note that ‘drvPath’ is only used for
475        informational purposes. */
476     virtual BuildResult buildDerivation(const Path & drvPath, const BasicDerivation & drv,
477         BuildMode buildMode = bmNormal) = 0;
478 
479     /* Ensure that a path is valid.  If it is not currently valid, it
480        may be made valid by running a substitute (if defined for the
481        path). */
482     virtual void ensurePath(const Path & path) = 0;
483 
484     /* Add a store path as a temporary root of the garbage collector.
485        The root disappears as soon as we exit. */
addTempRoot(const Path & path)486     virtual void addTempRoot(const Path & path)
487     { unsupported("addTempRoot"); }
488 
489     /* Add an indirect root, which is merely a symlink to `path' from
490        /nix/var/nix/gcroots/auto/<hash of `path'>.  `path' is supposed
491        to be a symlink to a store path.  The garbage collector will
492        automatically remove the indirect root when it finds that
493        `path' has disappeared. */
addIndirectRoot(const Path & path)494     virtual void addIndirectRoot(const Path & path)
495     { unsupported("addIndirectRoot"); }
496 
497     /* Acquire the global GC lock, then immediately release it.  This
498        function must be called after registering a new permanent root,
499        but before exiting.  Otherwise, it is possible that a running
500        garbage collector doesn't see the new root and deletes the
501        stuff we've just built.  By acquiring the lock briefly, we
502        ensure that either:
503 
504        - The collector is already running, and so we block until the
505          collector is finished.  The collector will know about our
506          *temporary* locks, which should include whatever it is we
507          want to register as a permanent lock.
508 
509        - The collector isn't running, or it's just started but hasn't
510          acquired the GC lock yet.  In that case we get and release
511          the lock right away, then exit.  The collector scans the
512          permanent root and sees our's.
513 
514        In either case the permanent root is seen by the collector. */
syncWithGC()515     virtual void syncWithGC() { };
516 
517     /* Find the roots of the garbage collector.  Each root is a pair
518        (link, storepath) where `link' is the path of the symlink
519        outside of the Nix store that point to `storePath'. If
520        'censor' is true, privacy-sensitive information about roots
521        found in /proc is censored. */
findRoots(bool censor)522     virtual Roots findRoots(bool censor)
523     { unsupported("findRoots"); }
524 
525     /* Perform a garbage collection. */
collectGarbage(const GCOptions & options,GCResults & results)526     virtual void collectGarbage(const GCOptions & options, GCResults & results)
527     { unsupported("collectGarbage"); }
528 
529     /* Return a string representing information about the path that
530        can be loaded into the database using `nix-store --load-db' or
531        `nix-store --register-validity'. */
532     string makeValidityRegistration(const PathSet & paths,
533         bool showDerivers, bool showHash);
534 
535     /* Write a JSON representation of store path metadata, such as the
536        hash and the references. If ‘includeImpureInfo’ is true,
537        variable elements such as the registration time are
538        included. If ‘showClosureSize’ is true, the closure size of
539        each path is included. */
540     void pathInfoToJSON(JSONPlaceholder & jsonOut, const PathSet & storePaths,
541         bool includeImpureInfo, bool showClosureSize,
542         AllowInvalidFlag allowInvalid = DisallowInvalid);
543 
544     /* Return the size of the closure of the specified path, that is,
545        the sum of the size of the NAR serialisation of each path in
546        the closure. */
547     std::pair<uint64_t, uint64_t> getClosureSize(const Path & storePath);
548 
549     /* Optimise the disk space usage of the Nix store by hard-linking files
550        with the same contents. */
optimiseStore()551     virtual void optimiseStore() { };
552 
553     /* Check the integrity of the Nix store.  Returns true if errors
554        remain. */
verifyStore(bool checkContents,RepairFlag repair=NoRepair)555     virtual bool verifyStore(bool checkContents, RepairFlag repair = NoRepair) { return false; };
556 
557     /* Return an object to access files in the Nix store. */
getFSAccessor()558     virtual ref<FSAccessor> getFSAccessor()
559     { unsupported("getFSAccessor"); }
560 
561     /* Add signatures to the specified store path. The signatures are
562        not verified. */
addSignatures(const Path & storePath,const StringSet & sigs)563     virtual void addSignatures(const Path & storePath, const StringSet & sigs)
564     { unsupported("addSignatures"); }
565 
566     /* Utility functions. */
567 
568     /* Read a derivation, after ensuring its existence through
569        ensurePath(). */
570     Derivation derivationFromPath(const Path & drvPath);
571 
572     /* Place in `out' the set of all store paths in the file system
573        closure of `storePath'; that is, all paths than can be directly
574        or indirectly reached from it.  `out' is not cleared.  If
575        `flipDirection' is true, the set of paths that can reach
576        `storePath' is returned; that is, the closures under the
577        `referrers' relation instead of the `references' relation is
578        returned. */
579     virtual void computeFSClosure(const PathSet & paths,
580         PathSet & out, bool flipDirection = false,
581         bool includeOutputs = false, bool includeDerivers = false);
582 
583     void computeFSClosure(const Path & path,
584         PathSet & out, bool flipDirection = false,
585         bool includeOutputs = false, bool includeDerivers = false);
586 
587     /* Given a set of paths that are to be built, return the set of
588        derivations that will be built, and the set of output paths
589        that will be substituted. */
590     virtual void queryMissing(const PathSet & targets,
591         PathSet & willBuild, PathSet & willSubstitute, PathSet & unknown,
592         unsigned long long & downloadSize, unsigned long long & narSize);
593 
594     /* Sort a set of paths topologically under the references
595        relation.  If p refers to q, then p precedes q in this list. */
596     Paths topoSortPaths(const PathSet & paths);
597 
598     /* Export multiple paths in the format expected by ‘nix-store
599        --import’. */
600     void exportPaths(const Paths & paths, Sink & sink);
601 
602     void exportPath(const Path & path, Sink & sink);
603 
604     /* Import a sequence of NAR dumps created by exportPaths() into
605        the Nix store. Optionally, the contents of the NARs are
606        preloaded into the specified FS accessor to speed up subsequent
607        access. */
608     Paths importPaths(Source & source, std::shared_ptr<FSAccessor> accessor,
609         CheckSigsFlag checkSigs = CheckSigs);
610 
611     struct Stats
612     {
613         std::atomic<uint64_t> narInfoRead{0};
614         std::atomic<uint64_t> narInfoReadAverted{0};
615         std::atomic<uint64_t> narInfoMissing{0};
616         std::atomic<uint64_t> narInfoWrite{0};
617         std::atomic<uint64_t> pathInfoCacheSize{0};
618         std::atomic<uint64_t> narRead{0};
619         std::atomic<uint64_t> narReadBytes{0};
620         std::atomic<uint64_t> narReadCompressedBytes{0};
621         std::atomic<uint64_t> narWrite{0};
622         std::atomic<uint64_t> narWriteAverted{0};
623         std::atomic<uint64_t> narWriteBytes{0};
624         std::atomic<uint64_t> narWriteCompressedBytes{0};
625         std::atomic<uint64_t> narWriteCompressionTimeMs{0};
626     };
627 
628     const Stats & getStats();
629 
630     /* Return the build log of the specified store path, if available,
631        or null otherwise. */
getBuildLog(const Path & path)632     virtual std::shared_ptr<std::string> getBuildLog(const Path & path)
633     { return nullptr; }
634 
635     /* Hack to allow long-running processes like hydra-queue-runner to
636        occasionally flush their path info cache. */
clearPathInfoCache()637     void clearPathInfoCache()
638     {
639         state.lock()->pathInfoCache.clear();
640     }
641 
642     /* Establish a connection to the store, for store types that have
643        a notion of connection. Otherwise this is a no-op. */
connect()644     virtual void connect() { };
645 
646     /* Get the protocol version of this store or it's connection. */
getProtocol()647     virtual unsigned int getProtocol()
648     {
649         return 0;
650     };
651 
652     /* Get the priority of the store, used to order substituters. In
653        particular, binary caches can specify a priority field in their
654        "nix-cache-info" file. Lower value means higher priority. */
getPriority()655     virtual int getPriority() { return 0; }
656 
toRealPath(const Path & storePath)657     virtual Path toRealPath(const Path & storePath)
658     {
659         return storePath;
660     }
661 
createUser(const std::string & userName,uid_t userId)662     virtual void createUser(const std::string & userName, uid_t userId)
663     { }
664 
665 protected:
666 
667     Stats stats;
668 
669     /* Unsupported methods. */
unsupported(const std::string & op)670     [[noreturn]] void unsupported(const std::string & op)
671     {
672         throw Unsupported("operation '%s' is not supported by store '%s'", op, getUri());
673     }
674 
675 };
676 
677 
678 class LocalFSStore : public virtual Store
679 {
680 public:
681 
682     // FIXME: the (Store*) cast works around a bug in gcc that causes
683     // it to emit the call to the Option constructor. Clang works fine
684     // either way.
685     const PathSetting rootDir{(Store*) this, true, "",
686         "root", "directory prefixed to all other paths"};
687     const PathSetting stateDir{(Store*) this, false,
688         rootDir != "" ? rootDir + "/nix/var/nix" : settings.nixStateDir,
689         "state", "directory where Nix will store state"};
690     const PathSetting logDir{(Store*) this, false,
691         rootDir != "" ? rootDir + "/nix/var/log/nix" : settings.nixLogDir,
692         "log", "directory where Nix will store state"};
693 
694     const static string drvsLogDir;
695 
696     LocalFSStore(const Params & params);
697 
698     void narFromPath(const Path & path, Sink & sink) override;
699     ref<FSAccessor> getFSAccessor() override;
700 
701     /* Register a permanent GC root. */
702     Path addPermRoot(const Path & storePath,
703         const Path & gcRoot, bool indirect, bool allowOutsideRootsDir = false);
704 
getRealStoreDir()705     virtual Path getRealStoreDir() { return storeDir; }
706 
toRealPath(const Path & storePath)707     Path toRealPath(const Path & storePath) override
708     {
709         assert(isInStore(storePath));
710         return getRealStoreDir() + "/" + std::string(storePath, storeDir.size() + 1);
711     }
712 
713     std::shared_ptr<std::string> getBuildLog(const Path & path) override;
714 };
715 
716 
717 /* Extract the name part of the given store path. */
718 string storePathToName(const Path & path);
719 
720 /* Extract the hash part of the given store path. */
721 string storePathToHash(const Path & path);
722 
723 /* Check whether ‘name’ is a valid store path name part, i.e. contains
724    only the characters [a-zA-Z0-9\+\-\.\_\?\=] and doesn't start with
725    a dot. */
726 void checkStoreName(const string & name);
727 
728 
729 /* Copy a path from one store to another. */
730 void copyStorePath(ref<Store> srcStore, ref<Store> dstStore,
731     const Path & storePath, RepairFlag repair = NoRepair, CheckSigsFlag checkSigs = CheckSigs);
732 
733 
734 /* Copy store paths from one store to another. The paths may be copied
735    in parallel. They are copied in a topologically sorted order
736    (i.e. if A is a reference of B, then A is copied before B), but
737    the set of store paths is not automatically closed; use
738    copyClosure() for that. */
739 void copyPaths(ref<Store> srcStore, ref<Store> dstStore, const PathSet & storePaths,
740     RepairFlag repair = NoRepair,
741     CheckSigsFlag checkSigs = CheckSigs,
742     SubstituteFlag substitute = NoSubstitute);
743 
744 
745 /* Copy the closure of the specified paths from one store to another. */
746 void copyClosure(ref<Store> srcStore, ref<Store> dstStore,
747     const PathSet & storePaths,
748     RepairFlag repair = NoRepair,
749     CheckSigsFlag checkSigs = CheckSigs,
750     SubstituteFlag substitute = NoSubstitute);
751 
752 
753 /* Remove the temporary roots file for this process.  Any temporary
754    root becomes garbage after this point unless it has been registered
755    as a (permanent) root. */
756 void removeTempRoots();
757 
758 
759 /* Return a Store object to access the Nix store denoted by
760    ‘uri’ (slight misnomer...). Supported values are:
761 
762    * ‘local’: The Nix store in /nix/store and database in
763      /nix/var/nix/db, accessed directly.
764 
765    * ‘daemon’: The Nix store accessed via a Unix domain socket
766      connection to nix-daemon.
767 
768    * ‘unix://<path>’: The Nix store accessed via a Unix domain socket
769      connection to nix-daemon, with the socket located at <path>.
770 
771    * ‘auto’ or ‘’: Equivalent to ‘local’ or ‘daemon’ depending on
772      whether the user has write access to the local Nix
773      store/database.
774 
775    * ‘file://<path>’: A binary cache stored in <path>.
776 
777    * ‘https://<path>’: A binary cache accessed via HTTP.
778 
779    * ‘s3://<path>’: A writable binary cache stored on Amazon's Simple
780      Storage Service.
781 
782    * ‘ssh://[user@]<host>’: A remote Nix store accessed by running
783      ‘nix-store --serve’ via SSH.
784 
785    You can pass parameters to the store implementation by appending
786    ‘?key=value&key=value&...’ to the URI.
787 */
788 ref<Store> openStore(const std::string & uri = settings.storeUri.get(),
789     const Store::Params & extraParams = Store::Params());
790 
791 
792 enum StoreType {
793     tDaemon,
794     tLocal,
795     tOther
796 };
797 
798 
799 StoreType getStoreType(const std::string & uri = settings.storeUri.get(),
800     const std::string & stateDir = settings.nixStateDir);
801 
802 /* Return the default substituter stores, defined by the
803    ‘substituters’ option and various legacy options. */
804 std::list<ref<Store>> getDefaultSubstituters();
805 
806 
807 /* Store implementation registration. */
808 typedef std::function<std::shared_ptr<Store>(
809     const std::string & uri, const Store::Params & params)> OpenStore;
810 
811 struct RegisterStoreImplementation
812 {
813     typedef std::vector<OpenStore> Implementations;
814     static Implementations * implementations;
815 
RegisterStoreImplementationnix::RegisterStoreImplementation816     RegisterStoreImplementation(OpenStore fun)
817     {
818         if (!implementations) implementations = new Implementations;
819         implementations->push_back(fun);
820     }
821 };
822 
823 
824 
825 /* Display a set of paths in human-readable form (i.e., between quotes
826    and separated by commas). */
827 string showPaths(const PathSet & paths);
828 
829 
830 ValidPathInfo decodeValidPathInfo(std::istream & str,
831     bool hashGiven = false);
832 
833 
834 /* Compute the content-addressability assertion (ValidPathInfo::ca)
835    for paths created by makeFixedOutputPath() / addToStore(). */
836 std::string makeFixedOutputCA(bool recursive, const Hash & hash);
837 
838 
839 /* Split URI into protocol+hierarchy part and its parameter set. */
840 std::pair<std::string, Store::Params> splitUriAndParams(const std::string & uri);
841 
842 }
843