@@ -1563,38 +1563,239 @@ fs.unwatchFile = function(filename, listener) {
15631563} ;
15641564
15651565
1566- fs . realpathSync = function realpathSync ( path , options ) {
1566+ // Regexp that finds the next portion of a (partial) path
1567+ // result is [base_with_slash, base], e.g. ['somedir/', 'somedir']
1568+ const nextPartRe = isWindows ?
1569+ / ( .* ?) (?: [ \/ \\ ] + | $ ) / g :
1570+ / ( .* ?) (?: [ \/ ] + | $ ) / g;
1571+
1572+ // Regex to find the device root, including trailing slash. E.g. 'c:\\'.
1573+ const splitRootRe = isWindows ?
1574+ / ^ (?: [ a - z A - Z ] : | [ \\ \/ ] { 2 } [ ^ \\ \/ ] + [ \\ \/ ] [ ^ \\ \/ ] + ) ? [ \\ \/ ] * / :
1575+ / ^ [ \/ ] * / ;
1576+
1577+ function encodeRealpathResult ( result , options , err ) {
1578+ if ( ! options || ! options . encoding || options . encoding === 'utf8' || err )
1579+ return result ;
1580+ const asBuffer = Buffer . from ( result ) ;
1581+ if ( options . encoding === 'buffer' ) {
1582+ return asBuffer ;
1583+ } else {
1584+ return asBuffer . toString ( options . encoding ) ;
1585+ }
1586+ }
1587+
1588+ fs . realpathSync = function realpathSync ( p , options ) {
15671589 if ( ! options )
15681590 options = { } ;
15691591 else if ( typeof options === 'string' )
15701592 options = { encoding : options } ;
15711593 else if ( typeof options !== 'object' )
15721594 throw new TypeError ( '"options" must be a string or an object' ) ;
1573- nullCheck ( path ) ;
1574- return binding . realpath ( pathModule . _makeLong ( path ) , options . encoding ) ;
1595+ nullCheck ( p ) ;
1596+
1597+ p = p . toString ( 'utf8' ) ;
1598+ p = pathModule . resolve ( p ) ;
1599+
1600+ const seenLinks = { } ;
1601+ const knownHard = { } ;
1602+
1603+ // current character position in p
1604+ var pos ;
1605+ // the partial path so far, including a trailing slash if any
1606+ var current ;
1607+ // the partial path without a trailing slash (except when pointing at a root)
1608+ var base ;
1609+ // the partial path scanned in the previous round, with slash
1610+ var previous ;
1611+
1612+ start ( ) ;
1613+
1614+ function start ( ) {
1615+ // Skip over roots
1616+ var m = splitRootRe . exec ( p ) ;
1617+ pos = m [ 0 ] . length ;
1618+ current = m [ 0 ] ;
1619+ base = m [ 0 ] ;
1620+ previous = '' ;
1621+
1622+ // On windows, check that the root exists. On unix there is no need.
1623+ if ( isWindows && ! knownHard [ base ] ) {
1624+ fs . lstatSync ( base ) ;
1625+ knownHard [ base ] = true ;
1626+ }
1627+ }
1628+
1629+ // walk down the path, swapping out linked pathparts for their real
1630+ // values
1631+ // NB: p.length changes.
1632+ while ( pos < p . length ) {
1633+ // find the next part
1634+ nextPartRe . lastIndex = pos ;
1635+ var result = nextPartRe . exec ( p ) ;
1636+ previous = current ;
1637+ current += result [ 0 ] ;
1638+ base = previous + result [ 1 ] ;
1639+ pos = nextPartRe . lastIndex ;
1640+
1641+ // continue if not a symlink
1642+ if ( knownHard [ base ] ) {
1643+ continue ;
1644+ }
1645+
1646+ var resolvedLink ;
1647+ var stat = fs . lstatSync ( base ) ;
1648+ if ( ! stat . isSymbolicLink ( ) ) {
1649+ knownHard [ base ] = true ;
1650+ continue ;
1651+ }
1652+
1653+ // read the link if it wasn't read before
1654+ // dev/ino always return 0 on windows, so skip the check.
1655+ var linkTarget = null ;
1656+ if ( ! isWindows ) {
1657+ var id = stat . dev . toString ( 32 ) + ':' + stat . ino . toString ( 32 ) ;
1658+ if ( seenLinks . hasOwnProperty ( id ) ) {
1659+ linkTarget = seenLinks [ id ] ;
1660+ }
1661+ }
1662+ if ( linkTarget === null ) {
1663+ fs . statSync ( base ) ;
1664+ linkTarget = fs . readlinkSync ( base ) ;
1665+ }
1666+ resolvedLink = pathModule . resolve ( previous , linkTarget ) ;
1667+
1668+ if ( ! isWindows ) seenLinks [ id ] = linkTarget ;
1669+
1670+ // resolve the link, then start over
1671+ p = pathModule . resolve ( resolvedLink , p . slice ( pos ) ) ;
1672+ start ( ) ;
1673+ }
1674+
1675+ return encodeRealpathResult ( p , options ) ;
15751676} ;
15761677
15771678
1578- fs . realpath = function realpath ( path , options , callback ) {
1679+ fs . realpath = function realpath ( p , options , callback ) {
1680+ if ( typeof callback !== 'function' ) {
1681+ callback = maybeCallback ( options ) ;
1682+ options = { } ;
1683+ }
1684+
15791685 if ( ! options ) {
15801686 options = { } ;
15811687 } else if ( typeof options === 'function' ) {
1582- callback = options ;
15831688 options = { } ;
15841689 } else if ( typeof options === 'string' ) {
15851690 options = { encoding : options } ;
15861691 } else if ( typeof options !== 'object' ) {
15871692 throw new TypeError ( '"options" must be a string or an object' ) ;
15881693 }
1589- callback = makeCallback ( callback ) ;
1590- if ( ! nullCheck ( path , callback ) )
1694+ if ( ! nullCheck ( p , callback ) )
15911695 return ;
1592- var req = new FSReqWrap ( ) ;
1593- req . oncomplete = callback ;
1594- binding . realpath ( pathModule . _makeLong ( path ) , options . encoding , req ) ;
1595- return ;
1596- } ;
15971696
1697+ p = p . toString ( 'utf8' ) ;
1698+ p = pathModule . resolve ( p ) ;
1699+
1700+ const seenLinks = { } ;
1701+ const knownHard = { } ;
1702+
1703+ // current character position in p
1704+ var pos ;
1705+ // the partial path so far, including a trailing slash if any
1706+ var current ;
1707+ // the partial path without a trailing slash (except when pointing at a root)
1708+ var base ;
1709+ // the partial path scanned in the previous round, with slash
1710+ var previous ;
1711+
1712+ start ( ) ;
1713+
1714+ function start ( ) {
1715+ // Skip over roots
1716+ var m = splitRootRe . exec ( p ) ;
1717+ pos = m [ 0 ] . length ;
1718+ current = m [ 0 ] ;
1719+ base = m [ 0 ] ;
1720+ previous = '' ;
1721+
1722+ // On windows, check that the root exists. On unix there is no need.
1723+ if ( isWindows && ! knownHard [ base ] ) {
1724+ fs . lstat ( base , function ( err ) {
1725+ if ( err ) return callback ( err ) ;
1726+ knownHard [ base ] = true ;
1727+ LOOP ( ) ;
1728+ } ) ;
1729+ } else {
1730+ process . nextTick ( LOOP ) ;
1731+ }
1732+ }
1733+
1734+ // walk down the path, swapping out linked pathparts for their real
1735+ // values
1736+ function LOOP ( ) {
1737+ // stop if scanned past end of path
1738+ if ( pos >= p . length ) {
1739+ return callback ( null , encodeRealpathResult ( p , options ) ) ;
1740+ }
1741+
1742+ // find the next part
1743+ nextPartRe . lastIndex = pos ;
1744+ var result = nextPartRe . exec ( p ) ;
1745+ previous = current ;
1746+ current += result [ 0 ] ;
1747+ base = previous + result [ 1 ] ;
1748+ pos = nextPartRe . lastIndex ;
1749+
1750+ // continue if not a symlink
1751+ if ( knownHard [ base ] ) {
1752+ return process . nextTick ( LOOP ) ;
1753+ }
1754+
1755+ return fs . lstat ( base , gotStat ) ;
1756+ }
1757+
1758+ function gotStat ( err , stat ) {
1759+ if ( err ) return callback ( err ) ;
1760+
1761+ // if not a symlink, skip to the next path part
1762+ if ( ! stat . isSymbolicLink ( ) ) {
1763+ knownHard [ base ] = true ;
1764+ return process . nextTick ( LOOP ) ;
1765+ }
1766+
1767+ // stat & read the link if not read before
1768+ // call gotTarget as soon as the link target is known
1769+ // dev/ino always return 0 on windows, so skip the check.
1770+ if ( ! isWindows ) {
1771+ var id = stat . dev . toString ( 32 ) + ':' + stat . ino . toString ( 32 ) ;
1772+ if ( seenLinks . hasOwnProperty ( id ) ) {
1773+ return gotTarget ( null , seenLinks [ id ] , base ) ;
1774+ }
1775+ }
1776+ fs . stat ( base , function ( err ) {
1777+ if ( err ) return callback ( err ) ;
1778+
1779+ fs . readlink ( base , function ( err , target ) {
1780+ if ( ! isWindows ) seenLinks [ id ] = target ;
1781+ gotTarget ( err , target ) ;
1782+ } ) ;
1783+ } ) ;
1784+ }
1785+
1786+ function gotTarget ( err , target , base ) {
1787+ if ( err ) return callback ( err ) ;
1788+
1789+ var resolvedLink = pathModule . resolve ( previous , target ) ;
1790+ gotResolvedLink ( resolvedLink ) ;
1791+ }
1792+
1793+ function gotResolvedLink ( resolvedLink ) {
1794+ // resolve the link, then start over
1795+ p = pathModule . resolve ( resolvedLink , p . slice ( pos ) ) ;
1796+ start ( ) ;
1797+ }
1798+ } ;
15981799
15991800fs . mkdtemp = function ( prefix , options , callback ) {
16001801 if ( ! prefix || typeof prefix !== 'string' )
0 commit comments