fix(snapshot): surface cursor close errors
- commit
- 91d6720c5323213216fde21ea9b8d050eb5b19b4
- author
- brice · · 2026-07-21 21:29 UTC
- parent
- 11815fb
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
1 file · +14 -3
M internal/adapters/snapshot/maintenance.go +14 -3
| @@ -260,12 +260,23 @@ func (r *Repository) readMaintenanceDir(dir string, n int, purpose string) ([]ma | |||
| 260 | 260 | // readMaintenanceDirent uses the Linux getdents seek cookie from each record. | |
| 261 | 261 | // syscall.Dirent's Off field is the d_off member of linux_dirent64 and | |
| 262 | 262 | // syscall.Seek is lseek(2), as defined by Go's syscall Linux sources. | |
| 263 | - | func readMaintenanceDirent(dir string, limit int, cursor *maintenanceCursor) ([]maintenanceDirEntry, bool, error) { | |
| 263 | + | func readMaintenanceDirent(dir string, limit int, cursor *maintenanceCursor) (entries []maintenanceDirEntry, done bool, err error) { | |
| 264 | 264 | file, err := os.Open(dir) | |
| 265 | 265 | if err != nil { | |
| 266 | 266 | return nil, false, err | |
| 267 | 267 | } | |
| 268 | - | defer file.Close() | |
| 268 | + | defer func() { | |
| 269 | + | if closeErr := file.Close(); closeErr != nil { | |
| 270 | + | closeErr = fmt.Errorf("close maintenance directory %q: %w", dir, closeErr) | |
| 271 | + | if err != nil { | |
| 272 | + | err = errors.Join(err, closeErr) | |
| 273 | + | } else { | |
| 274 | + | entries = nil | |
| 275 | + | done = false | |
| 276 | + | err = closeErr | |
| 277 | + | } | |
| 278 | + | } | |
| 279 | + | }() | |
| 269 | 280 | fd := int(file.Fd()) | |
| 270 | 281 | if cursor.offset != 0 { | |
| 271 | 282 | if _, err := syscall.Seek(fd, cursor.offset, io.SeekStart); err != nil { | |
| @@ -273,7 +284,7 @@ func readMaintenanceDirent(dir string, limit int, cursor *maintenanceCursor) ([] | |||
| 273 | 284 | } | |
| 274 | 285 | } | |
| 275 | 286 | ||
| 276 | - | entries := make([]maintenanceDirEntry, 0, limit) | |
| 287 | + | entries = make([]maintenanceDirEntry, 0, limit) | |
| 277 | 288 | buffer := make([]byte, 8192) | |
| 278 | 289 | for len(entries) < limit { | |
| 279 | 290 | count, err := syscall.ReadDirent(fd, buffer) | |
| @@ -260,12 +260,23 @@ func (r *Repository) readMaintenanceDir(dir string, n int, purpose string) ([]ma | |||||
| 260 | // readMaintenanceDirent uses the Linux getdents seek cookie from each record. | 260 | // readMaintenanceDirent uses the Linux getdents seek cookie from each record. | ||
| 261 | // syscall.Dirent's Off field is the d_off member of linux_dirent64 and | 261 | // syscall.Dirent's Off field is the d_off member of linux_dirent64 and | ||
| 262 | // syscall.Seek is lseek(2), as defined by Go's syscall Linux sources. | 262 | // syscall.Seek is lseek(2), as defined by Go's syscall Linux sources. | ||
| 263 | - | func readMaintenanceDirent(dir string, limit int, cursor *maintenanceCursor) ([]maintenanceDirEntry, bool, error) { | 263 | + | func readMaintenanceDirent(dir string, limit int, cursor *maintenanceCursor) (entries []maintenanceDirEntry, done bool, err error) { |
| 264 | file, err := os.Open(dir) | 264 | file, err := os.Open(dir) | ||
| 265 | if err != nil { | 265 | if err != nil { | ||
| 266 | return nil, false, err | 266 | return nil, false, err | ||
| 267 | } | 267 | } | ||
| 268 | - | defer file.Close() | 268 | + | defer func() { |
| 269 | + | if closeErr := file.Close(); closeErr != nil { | |||
| 270 | + | closeErr = fmt.Errorf("close maintenance directory %q: %w", dir, closeErr) | |||
| 271 | + | if err != nil { | |||
| 272 | + | err = errors.Join(err, closeErr) | |||
| 273 | + | } else { | |||
| 274 | + | entries = nil | |||
| 275 | + | done = false | |||
| 276 | + | err = closeErr | |||
| 277 | + | } | |||
| 278 | + | } | |||
| 279 | + | }() | |||
| 269 | fd := int(file.Fd()) | 280 | fd := int(file.Fd()) | ||
| 270 | if cursor.offset != 0 { | 281 | if cursor.offset != 0 { | ||
| 271 | if _, err := syscall.Seek(fd, cursor.offset, io.SeekStart); err != nil { | 282 | if _, err := syscall.Seek(fd, cursor.offset, io.SeekStart); err != nil { | ||
| @@ -273,7 +284,7 @@ func readMaintenanceDirent(dir string, limit int, cursor *maintenanceCursor) ([] | |||||
| 273 | } | 284 | } | ||
| 274 | } | 285 | } | ||
| 275 | 286 | ||||
| 276 | - | entries := make([]maintenanceDirEntry, 0, limit) | 287 | + | entries = make([]maintenanceDirEntry, 0, limit) |
| 277 | buffer := make([]byte, 8192) | 288 | buffer := make([]byte, 8192) | ||
| 278 | for len(entries) < limit { | 289 | for len(entries) < limit { | ||
| 279 | count, err := syscall.ReadDirent(fd, buffer) | 290 | count, err := syscall.ReadDirent(fd, buffer) | ||