Projekt

Obecné

Profil

Stáhnout (1.69 KB) Statistiky
| Větev: | Revize:
1 3a515b92 cagy
const cache = new Map()
2
const fs = require('fs')
3
const { dirname, resolve } = require('path')
4
5
6
const lstat = path => new Promise((res, rej) =>
7
  fs.lstat(path, (er, st) => er ? rej(er) : res(st)))
8
9
const inferOwner = path => {
10
  path = resolve(path)
11
  if (cache.has(path))
12
    return Promise.resolve(cache.get(path))
13
14
  const statThen = st => {
15
    const { uid, gid } = st
16
    cache.set(path, { uid, gid })
17
    return { uid, gid }
18
  }
19
  const parent = dirname(path)
20
  const parentTrap = parent === path ? null : er => {
21
    return inferOwner(parent).then((owner) => {
22
      cache.set(path, owner)
23
      return owner
24
    })
25
  }
26
  return lstat(path).then(statThen, parentTrap)
27
}
28
29
const inferOwnerSync = path => {
30
  path = resolve(path)
31
  if (cache.has(path))
32
    return cache.get(path)
33
34
  const parent = dirname(path)
35
36
  // avoid obscuring call site by re-throwing
37
  // "catch" the error by returning from a finally,
38
  // only if we're not at the root, and the parent call works.
39
  let threw = true
40
  try {
41
    const st = fs.lstatSync(path)
42
    threw = false
43
    const { uid, gid } = st
44
    cache.set(path, { uid, gid })
45
    return { uid, gid }
46
  } finally {
47
    if (threw && parent !== path) {
48
      const owner = inferOwnerSync(parent)
49
      cache.set(path, owner)
50
      return owner // eslint-disable-line no-unsafe-finally
51
    }
52
  }
53
}
54
55
const inflight = new Map()
56
module.exports = path => {
57
  path = resolve(path)
58
  if (inflight.has(path))
59
    return Promise.resolve(inflight.get(path))
60
  const p = inferOwner(path).then(owner => {
61
    inflight.delete(path)
62
    return owner
63
  })
64
  inflight.set(path, p)
65
  return p
66
}
67
module.exports.sync = inferOwnerSync
68
module.exports.clearCache = () => {
69
  cache.clear()
70
  inflight.clear()
71
}