Skip to content

Commit 575a511

Browse files
committed
fix: reserve paths case-insensitively
The path reservation system prevents multiple file entries clobbering one another while in flight, while allowing maximal parallelization in unpacking otherwise. However, on case-insensitive file systems, this can still introduce a race condition if the entries in the archive have different cases, as capital and lowercase entries will not be treated as reserving the same path. Normalize slashes and cases immediately when reserving paths, such that paths which differ only in case or slash repetition are treated as identical paths.
1 parent d61628c commit 575a511

File tree

2 files changed

+4
-3
lines changed

2 files changed

+4
-3
lines changed

lib/path-reservations.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
const assert = require('assert')
1010
const normPath = require('./normalize-windows-path.js')
11+
const { join } = require('path')
1112

1213
module.exports = () => {
1314
// path => [function or Set]
@@ -19,9 +20,8 @@ module.exports = () => {
1920
const reservations = new Map()
2021

2122
// return a set of parent dirs for a given path
22-
const { join } = require('path')
2323
const getDirs = path =>
24-
normPath(join(path)).split('/').slice(0, -1).reduce((set, path) =>
24+
path.split('/').slice(0, -1).reduce((set, path) =>
2525
set.length ? set.concat(normPath(join(set[set.length - 1], path)))
2626
: [path], [])
2727

@@ -99,6 +99,7 @@ module.exports = () => {
9999
}
100100

101101
const reserve = (paths, fn) => {
102+
paths = paths.map(p => normPath(join(p)).toLowerCase())
102103
const dirs = new Set(
103104
paths.map(path => getDirs(path)).reduce((a, b) => a.concat(b))
104105
)

test/path-reservations.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ t.test('basic race', t => {
4949
}
5050

5151
t.ok(reserve(['a/b/c/d'], file), 'file starts right away')
52-
t.notOk(reserve(['a/b/c/d', 'a/b/e'], link), 'link waits')
52+
t.notOk(reserve(['a/B/c////D', 'a/b/e'], link), 'link waits')
5353
t.notOk(reserve(['a/b/e/f'], dir), 'dir waits')
5454
t.notOk(reserve(['a/b'], dir2), 'dir2 waits')
5555
t.notOk(reserve(['a/b/x'], dir3), 'dir3 waits')

0 commit comments

Comments
 (0)