summaryrefslogtreecommitdiff
path: root/guix
diff options
context:
space:
mode:
authorLudovic Courtès <ludo@gnu.org>2018-12-14 11:10:25 +0100
committerLudovic Courtès <ludo@gnu.org>2018-12-14 12:07:24 +0100
commitadb158b7396cbdcda347fa298978408e531a03fd (patch)
treefd6877e72a20840cd3962f80a89618bd08fcf04b /guix
parentea49fbdea3bbb9b55951b7bff9d9cf768fd23161 (diff)
deduplication: Gracefully handle ENOSPC raised by 'link' calls.
Reported by Andreas Enge <andreas@enge.fr> in <https://bugs.gnu.org/33676>. * guix/store/deduplication.scm (replace-with-link): Catch ENOSPC around 'get-temp-link'. Do nothing when 'get-temp-link' throws ENOSPC. Move code to restore PARENT's permissions outside of 'catch'. * tests/store-deduplication.scm ("deduplicate, ENOSPC"): New test.
Diffstat (limited to 'guix')
-rw-r--r--guix/store/deduplication.scm40
1 files changed, 27 insertions, 13 deletions
diff --git a/guix/store/deduplication.scm b/guix/store/deduplication.scm
index 21b0c81f3d..a777940f86 100644
--- a/guix/store/deduplication.scm
+++ b/guix/store/deduplication.scm
@@ -99,24 +99,38 @@ LINK-PREFIX."
(define* (replace-with-link target to-replace
#:key (swap-directory (dirname target)))
"Atomically replace the file TO-REPLACE with a link to TARGET. Use
-SWAP-DIRECTORY as the directory to store temporary hard links.
+SWAP-DIRECTORY as the directory to store temporary hard links. Upon ENOSPC
+and EMLINK, TO-REPLACE is left unchanged.
Note: TARGET, TO-REPLACE, and SWAP-DIRECTORY must be on the same file system."
- (let* ((temp-link (get-temp-link target swap-directory))
- (parent (dirname to-replace))
- (stat (stat parent)))
- (make-file-writable parent)
+ (define temp-link
(catch 'system-error
(lambda ()
- (rename-file temp-link to-replace)
-
- ;; Restore PARENT's mtime and permissions.
- (set-file-time parent stat)
- (chmod parent (stat:mode stat)))
+ (get-temp-link target swap-directory))
(lambda args
- (delete-file temp-link)
- (unless (= EMLINK (system-error-errno args))
- (apply throw args))))))
+ ;; We get ENOSPC when we can't fit an additional entry in
+ ;; SWAP-DIRECTORY.
+ (if (= ENOSPC (system-error-errno args))
+ #f
+ (apply throw args)))))
+
+ ;; If we couldn't create TEMP-LINK, that's OK: just don't do the
+ ;; replacement, which means TO-REPLACE won't be deduplicated.
+ (when temp-link
+ (let* ((parent (dirname to-replace))
+ (stat (stat parent)))
+ (make-file-writable parent)
+ (catch 'system-error
+ (lambda ()
+ (rename-file temp-link to-replace))
+ (lambda args
+ (delete-file temp-link)
+ (unless (= EMLINK (system-error-errno args))
+ (apply throw args))))
+
+ ;; Restore PARENT's mtime and permissions.
+ (set-file-time parent stat)
+ (chmod parent (stat:mode stat)))))
(define* (deduplicate path hash #:key (store %store-directory))
"Check if a store item with sha256 hash HASH already exists. If so,