deduplication: Restore directory mtime and permissions after deduplication.

Fixes <https://bugs.gnu.org/33361>.

* guix/store/deduplication.scm (replace-with-link): Call 'set-file-time'
and 'chmod' after 'rename-file'.
* tests/nar.scm ("restore-file-set with directories (signed, valid)"):
New test.
This commit is contained in:
Ludovic Courtès 2018-11-13 14:20:27 +01:00
parent 8390869811
commit f5a2724ae4
No known key found for this signature in database
GPG key ID: 090B11993D9AEBB5
2 changed files with 44 additions and 3 deletions

View file

@ -102,11 +102,17 @@ (define* (replace-with-link target to-replace
SWAP-DIRECTORY as the directory to store temporary hard links. SWAP-DIRECTORY as the directory to store temporary hard links.
Note: TARGET, TO-REPLACE, and SWAP-DIRECTORY must be on the same file system." Note: TARGET, TO-REPLACE, and SWAP-DIRECTORY must be on the same file system."
(let ((temp-link (get-temp-link target swap-directory))) (let* ((temp-link (get-temp-link target swap-directory))
(make-file-writable (dirname to-replace)) (parent (dirname to-replace))
(stat (stat parent)))
(make-file-writable parent)
(catch 'system-error (catch 'system-error
(lambda () (lambda ()
(rename-file temp-link to-replace)) (rename-file temp-link to-replace)
;; Restore PARENT's mtime and permissions.
(set-file-time parent stat)
(chmod parent (stat:mode stat)))
(lambda args (lambda args
(delete-file temp-link) (delete-file temp-link)
(unless (= EMLINK (system-error-errno args)) (unless (= EMLINK (system-error-errno args))

View file

@ -359,6 +359,41 @@ (define (touch file)
files)) files))
(every canonical-file? files))))))) (every canonical-file? files)))))))
(test-assert "restore-file-set with directories (signed, valid)"
;; <https://bugs.gnu.org/33361> describes a bug whereby directories
;; containing files subject to deduplication were not canonicalized--i.e.,
;; their mtime and permissions were not reset. Ensure that this bug is
;; gone.
(with-store store
(let* ((text1 (random-text))
(text2 (random-text))
(tree `("tree" directory
("a" regular (data ,text1))
("b" directory
("c" regular (data ,text2))
("d" regular (data ,text1))))) ;duplicate
(file (add-file-tree-to-store store tree))
(dump (call-with-bytevector-output-port
(cute export-paths store (list file) <>))))
(delete-paths store (list file))
(and (not (file-exists? file))
(let* ((source (open-bytevector-input-port dump))
(imported (restore-file-set source)))
(and (equal? imported (list file))
(file-exists? file)
(valid-path? store file)
(string=? text1
(call-with-input-file (string-append file "/a")
get-string-all))
(string=? text2
(call-with-input-file
(string-append file "/b/c")
get-string-all))
(= (stat:ino (stat (string-append file "/a"))) ;deduplication
(stat:ino (stat (string-append file "/b/d"))))
(every canonical-file?
(find-files file #:directories? #t))))))))
(test-assert "restore-file-set (missing signature)" (test-assert "restore-file-set (missing signature)"
(let/ec return (let/ec return
(with-store store (with-store store