You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
			
				
					72 lines
				
				1.7 KiB
			
		
		
			
		
	
	
					72 lines
				
				1.7 KiB
			| 
								 
											4 years ago
										 
									 | 
							
								const cache = new Map()
							 | 
						||
| 
								 | 
							
								const fs = require('fs')
							 | 
						||
| 
								 | 
							
								const { dirname, resolve } = require('path')
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const lstat = path => new Promise((res, rej) =>
							 | 
						||
| 
								 | 
							
								  fs.lstat(path, (er, st) => er ? rej(er) : res(st)))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const inferOwner = path => {
							 | 
						||
| 
								 | 
							
								  path = resolve(path)
							 | 
						||
| 
								 | 
							
								  if (cache.has(path))
							 | 
						||
| 
								 | 
							
								    return Promise.resolve(cache.get(path))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  const statThen = st => {
							 | 
						||
| 
								 | 
							
								    const { uid, gid } = st
							 | 
						||
| 
								 | 
							
								    cache.set(path, { uid, gid })
							 | 
						||
| 
								 | 
							
								    return { uid, gid }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  const parent = dirname(path)
							 | 
						||
| 
								 | 
							
								  const parentTrap = parent === path ? null : er => {
							 | 
						||
| 
								 | 
							
								    return inferOwner(parent).then((owner) => {
							 | 
						||
| 
								 | 
							
								      cache.set(path, owner)
							 | 
						||
| 
								 | 
							
								      return owner
							 | 
						||
| 
								 | 
							
								    })
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  return lstat(path).then(statThen, parentTrap)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const inferOwnerSync = path => {
							 | 
						||
| 
								 | 
							
								  path = resolve(path)
							 | 
						||
| 
								 | 
							
								  if (cache.has(path))
							 | 
						||
| 
								 | 
							
								    return cache.get(path)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  const parent = dirname(path)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // avoid obscuring call site by re-throwing
							 | 
						||
| 
								 | 
							
								  // "catch" the error by returning from a finally,
							 | 
						||
| 
								 | 
							
								  // only if we're not at the root, and the parent call works.
							 | 
						||
| 
								 | 
							
								  let threw = true
							 | 
						||
| 
								 | 
							
								  try {
							 | 
						||
| 
								 | 
							
								    const st = fs.lstatSync(path)
							 | 
						||
| 
								 | 
							
								    threw = false
							 | 
						||
| 
								 | 
							
								    const { uid, gid } = st
							 | 
						||
| 
								 | 
							
								    cache.set(path, { uid, gid })
							 | 
						||
| 
								 | 
							
								    return { uid, gid }
							 | 
						||
| 
								 | 
							
								  } finally {
							 | 
						||
| 
								 | 
							
								    if (threw && parent !== path) {
							 | 
						||
| 
								 | 
							
								      const owner = inferOwnerSync(parent)
							 | 
						||
| 
								 | 
							
								      cache.set(path, owner)
							 | 
						||
| 
								 | 
							
								      return owner // eslint-disable-line no-unsafe-finally
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const inflight = new Map()
							 | 
						||
| 
								 | 
							
								module.exports = path => {
							 | 
						||
| 
								 | 
							
								  path = resolve(path)
							 | 
						||
| 
								 | 
							
								  if (inflight.has(path))
							 | 
						||
| 
								 | 
							
								    return Promise.resolve(inflight.get(path))
							 | 
						||
| 
								 | 
							
								  const p = inferOwner(path).then(owner => {
							 | 
						||
| 
								 | 
							
								    inflight.delete(path)
							 | 
						||
| 
								 | 
							
								    return owner
							 | 
						||
| 
								 | 
							
								  })
							 | 
						||
| 
								 | 
							
								  inflight.set(path, p)
							 | 
						||
| 
								 | 
							
								  return p
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								module.exports.sync = inferOwnerSync
							 | 
						||
| 
								 | 
							
								module.exports.clearCache = () => {
							 | 
						||
| 
								 | 
							
								  cache.clear()
							 | 
						||
| 
								 | 
							
								  inflight.clear()
							 | 
						||
| 
								 | 
							
								}
							 |