mirror of
https://git.in.rschanz.org/ryan77627/guix.git
synced 2025-01-24 11:39:46 -05:00
nar: Really protect the temporary store directory from GC.
Prevents garbage collection of the temporary store directory while restoring a file set, as it could previously happen: <https://lists.gnu.org/archive/html/guix-devel/2014-04/msg00167.html>. * guix/nar.scm (temporary-store-directory): Rename to... (temporary-store-file): ... this. Use 'add-permanent-root' instead of 'add-indirect-root'. (with-temporary-store-file): New macro. (restore-one-item): New procedure, with code formerly in 'restore-file-set'. Use 'with-temporary-store-file'. (restore-file-set): Use it.
This commit is contained in:
parent
a9d2a10546
commit
6071b55e10
1 changed files with 96 additions and 65 deletions
105
guix/nar.scm
105
guix/nar.scm
|
@ -333,16 +333,15 @@ (define* (finalize-store-file source target
|
||||||
(when lock?
|
(when lock?
|
||||||
(unlock-store-file target)))))
|
(unlock-store-file target)))))
|
||||||
|
|
||||||
(define (temporary-store-directory)
|
(define (temporary-store-file)
|
||||||
"Return the file name of a temporary directory created in the store that is
|
"Return the file name of a temporary file created in the store that is
|
||||||
protected from garbage collection."
|
protected from garbage collection."
|
||||||
(let* ((template (string-append (%store-prefix) "/guix-XXXXXX"))
|
(let* ((template (string-append (%store-prefix) "/guix-XXXXXX"))
|
||||||
(port (mkstemp! template)))
|
(port (mkstemp! template)))
|
||||||
(close-port port)
|
(close-port port)
|
||||||
|
|
||||||
;; Make sure TEMPLATE is not collected while we populate it.
|
;; Make sure TEMPLATE is not collected while we populate it.
|
||||||
(with-store store
|
(add-permanent-root template)
|
||||||
(add-indirect-root store template))
|
|
||||||
|
|
||||||
;; There's a small window during which the GC could delete the file. Try
|
;; There's a small window during which the GC could delete the file. Try
|
||||||
;; again if that happens.
|
;; again if that happens.
|
||||||
|
@ -351,30 +350,25 @@ (define (temporary-store-directory)
|
||||||
;; It's up to the caller to create that file or directory.
|
;; It's up to the caller to create that file or directory.
|
||||||
(delete-file template)
|
(delete-file template)
|
||||||
template)
|
template)
|
||||||
(temporary-store-directory))))
|
(begin
|
||||||
|
(remove-permanent-root template)
|
||||||
|
(temporary-store-file)))))
|
||||||
|
|
||||||
(define* (restore-file-set port
|
(define-syntax-rule (with-temporary-store-file name body ...)
|
||||||
#:key (verify-signature? #t) (lock? #t)
|
"Evaluate BODY with NAME bound to the file name of a temporary store item
|
||||||
|
protected from GC."
|
||||||
|
(let ((name (temporary-store-file)))
|
||||||
|
(dynamic-wind
|
||||||
|
(const #t)
|
||||||
|
(lambda ()
|
||||||
|
body ...)
|
||||||
|
(lambda ()
|
||||||
|
(remove-permanent-root name)))))
|
||||||
|
|
||||||
|
(define* (restore-one-item port
|
||||||
|
#:key acl (verify-signature? #t) (lock? #t)
|
||||||
(log-port (current-error-port)))
|
(log-port (current-error-port)))
|
||||||
"Restore the file set read from PORT to the store. The format of the data
|
"Restore one store item from PORT; return its file name on success."
|
||||||
on PORT must be as created by 'export-paths'---i.e., a series of Nar-formatted
|
|
||||||
archives with interspersed meta-data joining them together, possibly with a
|
|
||||||
digital signature at the end. Log progress to LOG-PORT. Return the list of
|
|
||||||
files restored.
|
|
||||||
|
|
||||||
When LOCK? is #f, assume locks for the files to be restored are already held.
|
|
||||||
This is the case when the daemon calls a build hook.
|
|
||||||
|
|
||||||
Note that this procedure accesses the store directly, so it's only meant to be
|
|
||||||
used by the daemon's build hooks since they cannot call back to the daemon
|
|
||||||
while the locks are held."
|
|
||||||
(define %export-magic
|
|
||||||
;; Number used to identify genuine file set archives.
|
|
||||||
#x4558494e)
|
|
||||||
|
|
||||||
(define port*
|
|
||||||
;; Keep that one around, for error conditions.
|
|
||||||
port)
|
|
||||||
|
|
||||||
(define (assert-valid-signature signature hash file)
|
(define (assert-valid-signature signature hash file)
|
||||||
;; Bail out if SIGNATURE, which must be a string as produced by
|
;; Bail out if SIGNATURE, which must be a string as produced by
|
||||||
|
@ -416,16 +410,19 @@ (define (assert-valid-signature signature hash file)
|
||||||
(&nar-signature-error
|
(&nar-signature-error
|
||||||
(signature signature) (file file) (port port))))))))
|
(signature signature) (file file) (port port))))))))
|
||||||
|
|
||||||
(let loop ((n (read-long-long port))
|
(define %export-magic
|
||||||
(files '()))
|
;; Number used to identify genuine file set archives.
|
||||||
(case n
|
#x4558494e)
|
||||||
((0)
|
|
||||||
(reverse files))
|
(define port*
|
||||||
((1)
|
;; Keep that one around, for error conditions.
|
||||||
|
port)
|
||||||
|
|
||||||
(let-values (((port get-hash)
|
(let-values (((port get-hash)
|
||||||
(open-sha256-input-port port)))
|
(open-sha256-input-port port)))
|
||||||
(let ((temp (temporary-store-directory)))
|
(with-temporary-store-file temp
|
||||||
(restore-file port temp)
|
(restore-file port temp)
|
||||||
|
|
||||||
(let ((magic (read-int port)))
|
(let ((magic (read-int port)))
|
||||||
(unless (= magic %export-magic)
|
(unless (= magic %export-magic)
|
||||||
(raise (condition
|
(raise (condition
|
||||||
|
@ -453,14 +450,44 @@ (define (assert-valid-signature signature hash file)
|
||||||
(finalize-store-file temp file
|
(finalize-store-file temp file
|
||||||
#:references refs
|
#:references refs
|
||||||
#:deriver deriver
|
#:deriver deriver
|
||||||
#:lock? lock?)
|
#:lock? lock?))
|
||||||
(loop (read-long-long port)
|
|
||||||
(cons file files)))
|
|
||||||
(raise (condition
|
(raise (condition
|
||||||
(&message (message "imported file lacks \
|
(&message (message "imported file lacks \
|
||||||
a signature"))
|
a signature"))
|
||||||
(&nar-signature-error
|
(&nar-signature-error
|
||||||
(port port*) (file file) (signature #f)))))))))))
|
(port port*) (file file) (signature #f))))))
|
||||||
|
file)))))
|
||||||
|
|
||||||
|
(define* (restore-file-set port
|
||||||
|
#:key (verify-signature? #t) (lock? #t)
|
||||||
|
(log-port (current-error-port)))
|
||||||
|
"Restore the file set read from PORT to the store. The format of the data
|
||||||
|
on PORT must be as created by 'export-paths'---i.e., a series of Nar-formatted
|
||||||
|
archives with interspersed meta-data joining them together, possibly with a
|
||||||
|
digital signature at the end. Log progress to LOG-PORT. Return the list of
|
||||||
|
files restored.
|
||||||
|
|
||||||
|
When LOCK? is #f, assume locks for the files to be restored are already held.
|
||||||
|
This is the case when the daemon calls a build hook.
|
||||||
|
|
||||||
|
Note that this procedure accesses the store directly, so it's only meant to be
|
||||||
|
used by the daemon's build hooks since they cannot call back to the daemon
|
||||||
|
while the locks are held."
|
||||||
|
(define acl
|
||||||
|
(current-acl))
|
||||||
|
|
||||||
|
(let loop ((n (read-long-long port))
|
||||||
|
(files '()))
|
||||||
|
(case n
|
||||||
|
((0)
|
||||||
|
(reverse files))
|
||||||
|
((1)
|
||||||
|
(let ((file
|
||||||
|
(restore-one-item port
|
||||||
|
#:acl acl #:verify-signature? verify-signature?
|
||||||
|
#:lock? lock? #:log-port log-port)))
|
||||||
|
(loop (read-long-long port)
|
||||||
|
(cons file files))))
|
||||||
(else
|
(else
|
||||||
;; Neither 0 nor 1.
|
;; Neither 0 nor 1.
|
||||||
(raise (condition
|
(raise (condition
|
||||||
|
@ -468,4 +495,8 @@ (define (assert-valid-signature signature hash file)
|
||||||
(&nar-read-error
|
(&nar-read-error
|
||||||
(port port) (file #f) (token #f))))))))
|
(port port) (file #f) (token #f))))))))
|
||||||
|
|
||||||
|
;;; Local Variables:
|
||||||
|
;;; eval: (put 'with-temporary-store-file 'scheme-indent-function 1)
|
||||||
|
;;; End:
|
||||||
|
|
||||||
;;; nar.scm ends here
|
;;; nar.scm ends here
|
||||||
|
|
Loading…
Reference in a new issue