diff options
| author | Ludovic Courtès <ludo@gnu.org> | 2026-08-25 11:34:59 +0200 |
|---|---|---|
| committer | Ludovic Courtès <ludo@gnu.org> | 2026-08-27 14:41:25 +0200 |
| commit | 8a1a029f8fb6360d4b2c955e55f46b99f02a5c0f (patch) | |
| tree | 8bc26efd5950237126cd67897169284baac09f29 | |
| parent | 1a3d801d98f56cf3d915b21d17aa5f29b542ebb9 (diff) | |
cache: Avoid potential file descriptor leak.
There fixes two cases where ‘maybe-remove-expired-cache-entries’ could leak
‘expiry-port’ (in which case the underlying file descriptor would be closed
later, when ‘expiry-port’ gets GC’d.)
* guix/cache.scm (maybe-remove-expired-cache-entries): When ‘obsolete?’
returns false, explicitly close ‘expiry-port’. When it returns true, catch
errors around ‘seek’ block and close ‘expiry-port’ upon exception. Remove
ENOENT handling and comment that predates commit
d921c742b774a9f0a016f3db6442d5c58a330c92.
Signed-off-by: Ludovic Courtès <ludo@gnu.org>
Merges: #10795
| -rw-r--r-- | guix/cache.scm | 35 |
1 files changed, 19 insertions, 16 deletions
diff --git a/guix/cache.scm b/guix/cache.scm index 5d8a0edbaab..c1a12b17620 100644 --- a/guix/cache.scm +++ b/guix/cache.scm | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | ;;; GNU Guix --- Functional package management for GNU | 1 | ;;; GNU Guix --- Functional package management for GNU |
| 2 | ;;; Copyright © 2013-2017, 2020-2021, 2023-2024 Ludovic Courtès <ludo@gnu.org> | 2 | ;;; Copyright © 2013-2017, 2020-2021, 2023-2024, 2026 Ludovic Courtès <ludo@gnu.org> |
| 3 | ;;; Copyright © 2022 Simon Tournier <zimon.toutoune@gmail.com> | 3 | ;;; Copyright © 2022 Simon Tournier <zimon.toutoune@gmail.com> |
| 4 | ;;; | 4 | ;;; |
| 5 | ;;; This file is part of GNU Guix. | 5 | ;;; This file is part of GNU Guix. |
| @@ -107,20 +107,23 @@ CLEANUP-PERIOD denotes the minimum time between two cache cleanups." | |||
| 107 | 0) | 107 | 0) |
| 108 | +inf.0)) | 108 | +inf.0)) |
| 109 | 109 | ||
| 110 | (when (obsolete? last-expiry-date now cleanup-period) | 110 | (if (obsolete? last-expiry-date now cleanup-period) |
| 111 | (remove-expired-cache-entries (cache-entries cache) | 111 | (begin |
| 112 | #:now now | 112 | (remove-expired-cache-entries (cache-entries cache) |
| 113 | #:entry-expiration entry-expiration | 113 | #:now now |
| 114 | #:delete-entry delete-entry) | 114 | #:entry-expiration entry-expiration |
| 115 | (catch 'system-error | 115 | #:delete-entry delete-entry) |
| 116 | (lambda () | 116 | (catch #t |
| 117 | (seek expiry-port 0 SEEK_SET) | 117 | (lambda () |
| 118 | (truncate-file expiry-port 0) | 118 | (seek expiry-port 0 SEEK_SET) |
| 119 | (write (time-second now) expiry-port) | 119 | (truncate-file expiry-port 0) |
| 120 | (unlock-file expiry-port)) | 120 | (write (time-second now) expiry-port) |
| 121 | (lambda args | 121 | ;; Note: 'unlock-file' closes EXPIRY-PORT. |
| 122 | ;; ENOENT means CACHE does not exist. | 122 | (unlock-file expiry-port)) |
| 123 | (unless (= ENOENT (system-error-errno args)) | 123 | (lambda (key . args) |
| 124 | (apply throw args)))))) | 124 | (close-port expiry-port) |
| 125 | (apply throw key args)))) | ||
| 126 | (when expiry-port | ||
| 127 | (close-port expiry-port)))) | ||
| 125 | 128 | ||
| 126 | ;;; cache.scm ends here | 129 | ;;; cache.scm ends here |
